一、串口通信
实例:
#include<reg52.h>
sbit PIN_RXD = P3^0;//receive the pin
sbit PIN_TXD = P3^1;//the out pin
bit RxdEnd = 0;
bit RxdOrTxd = 0; //0是接收,1是发送
bit TxdEnd = 0;
unsigned char RxdBuf = 0;
unsigned char TxdBuf = 0;
void ConfigUART(unsigned int baud);
void StartRXD();
void StartTXD(unsigned char dat);
void main()
{
EA = 1;
ConfigUART(9600);
while(1)
{
while(PIN_RXD); //当检测到低电平时,开始接收
StartRXD(); //开始接收
while(!RxdEnd); //当检测到高电平时,表明接收完毕
StartTXD(RxdBuf + 1); //开始发送,数值加1
while(!TxdEnd);//当检测到高电平时,表明发送完毕
}
}
void ConfigUART(unsig63ned int baud) //设置波特率 X*12/11059200 = 1/baud TH0 + X = 256
{
TMOD &= 0xF0;
TMOD |= 0x02;//自动重装模式
TH0 = 256 - (11059200/12)/baud;
}
void StartRXD()
{
TL0 = 256 - ((256 - TH0)>>1);//读取中间值,右移一位,相当于除以2,
ET0 = 1;//使能时钟中断
TR0 = 1;//时钟中断开始
RxdEnd = 0;
RxdOrTxd = 0;
}
void StartTXD(unsigned char dat)
{
TxdBuf = dat;
TL0 = TH0;
ET0 = 1;
TR0 = 1;
PIN_TXD = 0;
TxdEnd = 0;
RxdOrTxd = 1;
}
void InterruptTimer0() interrupt 1
{
static unsigned char cnt = 0;
if(RxdOrTxd)
{
cnt++;
if(cnt <= 8)
{
PIN_TXD = TxdBuf & 0x01;//从最右边(最低位)开始发送
TxdBuf >>= 1; //发送完毕之后右移一位
}
else if(cnt == 9)
{
PIN_TXD = 1;
}
else
{
cnt = 0;
TR0 = 0; //关闭定时器
TxdEnd = 1;
}
}
else
{
if(cnt == 0)
{
if(!PIN_RXD)//检测低电平,开始接收
{
RxdBuf = 0; // 检测到低电平,
cnt++;
}
else
{
TR0 = 0;
}
}
else if(cnt <= 8)
{
RxdBuf >>= 1;
if(PIN_RXD)
{
RxdBuf |= 0x80;
}
cnt++;
}
else
{
cnt = 0;
TR0 = 0;
if(PIN_RXD)
{
RxdEnd = 1;
}
}
}
}
二、串行控制寄存器
注意:TI和RI需手动清零。在进行串口通信的时候,只需配置相关的寄存器即可
波特率的设置
SBUF:既是接收位,又是发送位,系统会自动识别
实例一:
#include<reg52.h>
void ConfigUART(unsigned int baud);
void main()
{
ConfigUART(9600);
while(1)
{
while(!RI)//RI为接收停止标志位,接收停止时置1
RI = 0;//RI徐手动复位
SBUF = SBUF + 1;//注意,这两个SBUF代表不同的存储区,前者为发送区,后者为接收区
while(!TI);//发送完毕后,TI置1
TI = 0;
}
}
void ConfigUART(unsigned int baud)
{
SCON = 0x50;//01010000,代表模式一,使能串口接收
TMOD &= 0x0F;
TMOD |= 0x20;//模式二,自动重装模式
TH1 = 256 - (11059200/12/32)/baud;//根据公式进行计算
TL1 = TH1;
ET1 = 0;//默认值为0,即关闭时钟中断一的功能,使其行驶波特率发生器的功能
TR1 = 1;//时钟1开始
}
实例二:数码管显示接收到的数值
#include <reg52.h>
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[7] = { //数码管+独立LED显示缓冲区
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char T0RH = 0; //T0重载值的高字节
unsigned char T0RL = 0; //T0重载值的低字节
unsigned char RxdByte = 0; //串口接收到的字节
void ConfigTimer0(unsigned int ms);
void ConfigUART(unsigned int baud);
void main()
{
EA = 1; //使能总中断
ENLED = 0; //选择数码管和独立LED
ADDR3 = 1;
ConfigTimer0(1); //配置T0定时1ms
ConfigUART(9600); //配置波特率为9600
while (1)
{ //将接收字节在数码管上以十六进制形式显示出来
LedBuff[0] = LedChar[RxdByte & 0x0F];
LedBuff[1] = LedChar[RxdByte >> 4];
}
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率
tmp = (tmp * ms) / 1000; //计算所需的计数值
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 18; //补偿中断响应延时造成的误差
T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
T0RL = (unsigned char)tmp;
TMOD &= 0xF0; //清零T0的控制位
TMOD |= 0x01; //配置T0为模式1
TH0 = T0RH; //加载T0重载值
TL0 = T0RL;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
SCON = 0x50; //配置串口为模式1
TMOD &= 0x0F; //清零T1的控制位
TMOD |= 0x20; //配置T1为模式2
TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值
TL1 = TH1; //初值等于重载值
ET1 = 0; //禁止T1中断
ES = 1; //使能串口中断
TR1 = 1; //启动T1
}
/* 按键扫描函数,需在定时中断中调用 */
void LedScan()
{
static unsigned char i = 0; //动态扫描索引
P0 = 0xFF; //关闭所有段选位,显示消隐
P1 = (P1 & 0xF8) | i; //位选索引值赋值到P1口低3位
P0 = LedBuff[i]; //缓冲区中索引位置的数据送到P0口
if (i < 6) //索引递增循环,遍历整个缓冲区
i++;
else
i = 0;
}
/* T0中断服务函数,完成LED扫描 */
void InterruptTimer0() interrupt 1
{
TH0 = T0RH; //重新加载重载值
TL0 = T0RL;
LedScan(); //LED扫描显示
}
/* UART中断服务函数 */
void InterruptUART() interrupt 4
{
if (RI) //接收到字节
{
RI = 0; //手动清零接收中断标志位
RxdByte = SBUF; //接收到的数据保存到接收字节变量中
SBUF = RxdByte; //接收到的数据又直接发回,叫作-"echo",
//用以提示用户输入的信息是否已正确接收
}
if (TI) //字节发送完毕
{
TI = 0; //手动清零发送中断标志位
}
}