找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 18213|回复: 1
收起左侧

C51单片机串口1收发字符串方法(程序)_最后修订无bug

[复制链接]
ID:26188 发表于 2015-2-18 01:28 | 显示全部楼层 |阅读模式
//此段包含串口1和定时器1的相关函数
/*串口编程示范说明==李斌20120802==========================================================
说明
串口接收ASCII字符,最大允许接收  Uart1_MaxString  个字符到Uart1_Data字符组,其中可包括回车
、换行符号,当接收到字0x00后,字符数组标示为可读,在字符串接收满后如果未接收到字0x00,所有
后续接收全部被忽略,直到接收到0x00,字符数组标示为可读。
使用22118400晶振,最大波特率19200bit/s
串口编程示范
//文件包含
#include "STC.H"
#include <stdio.h>
#include "Uart1.c"
//函数申明
void Uart1_setup();    //初使化串口函数申明,在函数中设定串口工作方式
//主函数
void main()
{
    printf("Helloo Word");                 //使用库函数向串口写数据,再使用printf前必须使用过Uart1_SendString函数
    while(1)                               //主程序循环避免死机
    {
        if(Uart1.Read==1)
        {                                  //如果串口1数据可读
            Uart1_SendString(Uart1_Data);  //串口1回送接收的数据
            Uart1.Read=0;                  //串口1不可读(已读,为下次读出做准备)
        }
    }
}
//初使化串口函数 ,必须写在主函数尾,在主函数头部申明并引用
void Uart1_setup()
{
for(Uart1.Data_P=0;Uart1.Data_P<=Uart1_MaxString;Uart1.Data_P++)
{//清空串口1接收字串内容,写0x00
    Uart1_Data[Uart1.Data_P]='\0';
}
Uart1.Data_P= 0;                //串口1接收字串下标归0
Uart1.ParitySet= 0;             //串口1使用9位可变波特率方式,校验方式为无校验, 0无校验,1:奇校验,2:偶校验,3:校验=1,4:校验=0
Uart1_Setup(19200,0);           //串口1波特率为19200bps,时基源选择定时器1 ,  0为定时器1,1为独立波特率发生器
}
=======================================================================================*/
//包含文件定义

//串口相关常量定义
#define  FOSC              22118400L   //系统频率11059200L 22118400L
#define  Uart1_MaxString   64          //串口1最大接收缓冲区字符数量
//串口相关变量定义
char  xdata          Uart1_Data[Uart1_MaxString+1]; //串口1接收字串
struct Uart1
{//串口1结构数据类型
    unsigned char        Data_P;                //串口1接收字串位置指针
    unsigned char        ParitySet;             //串口1奇偶校验方式 0不校验 1奇校验 2偶校验 3始终1 4始终0
    unsigned char        Busy:1;                //串口1正在发送标记,1,正在发送,0,发送完成 ,保留未使用
    unsigned char        Read:1;                //串口1接受字符组可读标记
    unsigned char        Parity:1;              //串口1接收到的奇偶校验状态 1,0
    unsigned char        Parity_out:1;          //串口1验证接收到的奇偶校验状态 1,验证,0验证错误
}Uart1;                                         //结构变量名
//Uart1包含函数申明
void Uart1_Setup(unsigned long Uart1_Baud,bit Uart1_Tx); //串口1波特率和时基源设置函数
void Uart1_chars_Int();                                  //串口1中断服务函数采用字符数组接收以'\0'为停止符的实际内容
void Uart1_SendData(unsigned char Uart1_dat);            //串口1单字符发送函数
void Uart1_SendString(char *s);                          //串口1字符串发送函数
//非必要包含的函数申明
//void Time1_Isr() interrupt 3 using 1;                  //定时器1中断服务函数入口
//void Uart1_Isr() interrupt 4 using 1;                  //串口1中断服务函数入口
/*********************************************************
** 函数名称: void Uart1_Setup(unsigned long Uart1_Baud,bit Uart1_Tx)
** 功能描述: 初始化串口函数
** 输   入: unsigned long Uart1_Baud,bit Uart1_Tx
** 输   出: 无
** 全局变量: PCON,SCON,TMOD,AUXR,TCON,TH1,
** 调用模块:
** 备    注:时钟为22118400Hz
            参数1:波特率设置,300;600;1200;2400;4800;9600;19200
            参数2:计数器选择,0,定时器1;1,独立波特率
**********************************************************/
void Uart1_Setup(unsigned long Uart1_Baud,bit Uart1_Tx)
{
unsigned int Uart1_Brt;       //串口定时器重装值临时存储位
//时基源设置-------------------------------------------------
if(Uart1_Tx)
{
    AUXR |= 0x01;  //串口1选择独立波特率发生器
}
else
{
    AUXR &= 0xFE;  //串口1选择定时器1做波特率发生器
}
//校验方式设置-------------------------------------------------
switch(Uart1.ParitySet)
{//判断校验方式
    case 1:SCON=0xD8;break;   //9位串口, 奇校验
    case 2:SCON=0xD4;break;   //9位串口, 偶校验
    case 3:SCON|=0xD8;break;  //9位串口, 掩码校验,校验值始终为 1
    case 4:SCON=0xD4;break;   //9位串口, 空校验
    default:
    {//8位串口, 无校验 Uart1.ParitySet=0; 校验位初值状态标记置0
        SCON&=0x5F;         //清除第5位,第7位
        SCON|=0x50;         //8位波特率可变,允许接收
        break;
    }
}
//波特率设置并开始运行串口-------------------------------------------------
//时钟为22118400Hz
Uart1_Brt=FOSC/32/Uart1_Baud;
if(Uart1_Brt>255)
{//如果重装值>255,使用12T模式12分频
    if(Uart1_Tx)
    {//如果使用独立波特率发生器
        AUXR &= 0xFB;                               //独立波特率使用12T模式
        BRT = 256-Uart1_Brt/12;                     //独立波特率发生器初值设置
        AUXR|= 0x10;                                //独立波特率发生器开始计数
    }
    else
    {//如果使用定时器1做波特率发生器
        TMOD&=0xCF;                                 //清除定时器1设置状态,定时器0不修改
        TMOD|=0x20;                                 //定时器1使用8位自动重装模式
        AUXR &= 0xBF;                               //定时器1使用12T模式
        TH1  = TL1 = 256-Uart1_Brt/12;              //设置自动装入的值
        //ET1  = 1;                                 //允许定时器1中断=========使用定时器1中断做串口中断时书写
        TR1  = 1;                                   //TCON|=0x40;定时器1开始计数,TCON&=0xBF;关闭计数
    }
}
else
{//如果重装值<255,使用1T模式1分频
    if(Uart1_Tx)
    {//如果使用独立波特率发生器
        AUXR |= 0x04;                               //独立波特率使用1T模式
        BRT  = 256-Uart1_Brt;                       //独立波特率发生器初值设置
        AUXR|= 0x10;                                //独立波特率发生器开始计数
    }
    else
    {//如果使用定时器1做波特率发生器
        TMOD&=0xCF;                                 //清除定时器1设置状态,定时器0不修改
        TMOD|=0x20;                                 //定时器1使用8位自动重装模式
        AUXR|=0x40;                                 //定时器1使用1T模式
        TH1  = TL1 = 256-Uart1_Brt;                 //设置自动装入的值
        //ET1  = 1;                                 //允许定时器1中断=========使用定时器1中断做串口中断时书写
        TR1  = 1;                                   //TCON|=0x40;定时器1开始计数,TCON&=0xBF;关闭计数
    }
}
    TI   = 1;                                       //兼容系统函数printf,需要先对TI置1
    ES        = 1;                                  //打开串口中断
    EA        = 1;                                  //打开总中断
}

//=======================================================================================
/**********************************************************
串口1中断服务函数
**********************************************************/
void Uart1_Isr() interrupt 4 using 1
{
Uart1_chars_Int();
}
void Uart1_chars_Int()
{
//EA=0;
    if (RI)
    {//如果 UART 接收产生中断
        RI = 0;                                           //清除 UART 接收中断标记
        //TF1=0;                                          //清除定时器1的中断标记,在使用串口中断时,这行不写
        ACC= SBUF;                                        //接收缓冲区数据写入累加器A
        Uart1.Parity = P;                                 //保存校验值到Uart1_Parity
        Uart1.Parity_out=0;                               //清除允许写入标记,为下面判断准备
        switch(Uart1.ParitySet)
        {//根据校验要求判断
            case 0:Uart1.Parity_out=1; break;                   //要求无校验,如果无校验,允许写入
            case 1:Uart1.Parity_out=Uart1.Parity^RB8; break;    //要求奇校验,如果检验结果和接收结果不符合则成立,允许写入
            case 2:Uart1.Parity_out=~(Uart1.Parity^RB8);break;  //要求偶校验,如果检验结果和接收结果符合则成立,允许写入
            case 3:Uart1.Parity_out=RB8; break;                 //要求常1校验,如果接收结果为1则成立,允许写入
            case 4:Uart1.Parity_out=~RB8; break;                //要求常0校验,如果接收结果为0则成立,允许写入
            default:Uart1.Parity_out=0;break;                   //非法的参数,不接收
        }
        if(Uart1.Parity_out)
        {//如果允许写入
            if(Uart1.Data_P<Uart1_MaxString)
            {//如果接受字符组指针小于字符数组最大下标减1(字符数组最后一位始终为0x00,方便指针做底判断)
                if(SBUF=='\0')
                {//如果接受字符是0x00
                    Uart1_Data[Uart1.Data_P]=SBUF;    //接受数据写入字符数组
                    Uart1.Data_P=0;                   //字符数组下标归0
                    Uart1.Read=1;                     //串口数据可读
                }
                else
                {//如果接受字符不是0x00
                    Uart1_Data[Uart1.Data_P]=SBUF;    //接受数据写入字符数组
                    Uart1.Data_P++;                   //字符数组下标自加1
                }
            }
            else
            {//如果接受字符组指针大于等于字符数组最大下标减1
                if(SBUF=='\0')
                {//如果接受字符是0x00
                    Uart1.Data_P=0;                   //字符数组下标归0
                    Uart1.Read=1;                     //串口数据可读
                }
            }
        }
    }
/*
    if (TI)
    {//如果 UART 发送产生中断
    }
*/
    /*=============使用定时器1中断时需要书写,使用串口中断时忽略
    if(TF1)
    {
        TF1=0;   //清定时器1中断标记
    }
    =============*/
//EA=1;
}

//=======================================================================================
/**********************************************************
** 函数名称: void Uart1_SendData(unsigned char Uart1_dat)
** 功能描述: UART1 单个字符发送函数
** 输   入: unsigned char Uart1_dat
** 输   出: 无
** 全局变量:
** 调用模块:
** 备    注:参数1:待发送的单个字符
**********************************************************/
void Uart1_SendData(unsigned char Uart1_dat)
{//UART 发送字节函数
bit TB8_Temp;
    ACC = Uart1_dat;                   //被发送数据送累加器A,准备求奇偶校验位 P
    TB8_Temp = P;                      //写奇偶校验标记
    while (~TI);                //循环等待正在发送标记被清空
TI=0;
    switch(Uart1.ParitySet)
    {//根据校验要求判断
        case 0:TB8=0;break;            //要求无校验
        case 1:TB8=~TB8_Temp;break;    //要求奇校验,翻转TB8的值
        case 2:TB8=TB8_Temp;break;     //偶校验,TB8不变
        case 3:TB8=1;break;            //要求常1校验,TB8恒等于1
        case 4:TB8=0;break;            //要求常0校验,TB8恒等于0
        default: break;                //要求无校验
    }
    SBUF = Uart1_dat;                  //累加器 A 中的数据送发送缓冲区发送

}
//=======================================================================================
/**********************************************************
** 函数名称: void Uart1_SendString(char *s)
** 功能描述: UART1 按字符串发送函数
** 输   入: char *s
** 输   出: 无
** 全局变量:
** 调用模块:
** 备    注:参数1:待发送的字符串
**********************************************************/
void Uart1_SendString(char *s)
{//UART 按字符串发送
    while (*s)
    {
        Uart1_SendData(*s++);   //将待发字符串依次使用SendData函数按字节发送
    }
}
//=======================================================================================
/*常用串口设置开关===============================附录====================================
AUXR |= 0x01;  //串口1选择独立波特率发生器
AUXR &= 0xFE;  //串口1选择定时器1做波特率发生器
AUXR |= 0x40;  //定时器1使用1T模式
AUXR &= 0xBF;  //定时器1使用12T模式
AUXR |= 0x04;  //独立波特率使用1T模式
AUXR &= 0xFB;  //独立波特率使用12T模式
AUXR |= 0x10;  //打开独立波特率发生器
AUXR &= 0xEF;  //关闭独立波特率发生器
PCON |= 0x80;  //串口1波特率加倍
PCON &= 0x7f;  //串口1波特率不加倍
AUXR |= 0x08;   //串口2波特率加倍
AUXR &= 0xf7;   //串口2波特率不加倍
==========================================================================================*/




回复

使用道具 举报

ID:98880 发表于 2018-5-22 23:14 | 显示全部楼层
这个可以做成模块化的吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表