第11章 UART串口通信
UART(Universal Asynchronous Receiver/Transmitter, 通用异步收发器)
波特率:baud,发送一位二进制数据的电平持续时间$ = \frac{1}{baud}$
在UART通信,规定:**当没有通信信号发生时,通信线路保持高电平,当要发送数据之前,先一位0表示起始位,然后发送8位数据位,数据位是先低后高的顺序,数据位发完后再发一位1表示停止位。
串口模块的波特率发生器只能由定时器T1或定时器T2产生,而不能由定时器T0产生,默认是使用定时器1的模式2,定时器T1的重载值计算公式为:TH1=TL1=256-晶振值/12/2/16/波特率
如果电源管理寄存器PCON的最高位=1,也就是如果PCON |=0x80;
,计算公式就写为:TH1=TL1=256-晶振值/12/16/波特率
;公式中的16重点说明,一位信号采集16次,取出第7、8、9次,如果这三次中有2次高电平,那么就认为是高电平,反之是低电平。
SBUF寄存器,地址:0x99
1. 利用定时器T0模拟串口通信程序
通过此程序能弄明白串口通信的原理
#include <reg52.h>
sbit TXD_PIN=P3^1; //
sbit RXD_PIN=P3^0; //
bit rxdOrTxd = 0; //
bit rxdEnd = 0; //
bit txdEnd = 0; //
unsigned char rxdBuf=0; //
unsigned char txdBuf=0; //
void configUART(unsigned int baud);
void startTx(unsigned char dat);
void startRx(void);
void main()
{
EA=1;
configUART(4800);
while(1)
{
while(!RXD_PIN); //
startRx();
while(!rxdEnd);
startTx(rxdBuf+1);
while(!txdEnd);
}
}
/**
* 名称:configUART
* 功能:T0中断配置函数
* 参数:baud——串口波特率
**/
void configUART(unsigned int baud)
{
unsigned int tmp;
tmp=12000000/12/baud; //256-TH0+(256-TH0)/2=
TH0=256-tmp;
TL0=TH0;
TMOD &=0XF0;
TMOD |=0x02;
}
/**
* 名称:
* 功能:启动串口接收
* 参数:
**/
void startRx()
{
TL0=256-((256-TH0)>>1); //开始接收时,波特率减半,增大周期为原来的2倍
ET0=1;
TR0=1;
rxdOrTxd=0;
rxdEnd=0;
}
/**
* 名称:
* 功能:启动串口发送
* 参数:dat——要发送的字节
**/
void startTx(unsigned char dat)
{
txdBuf=dat; //
TL0=TH0; //
ET0=1; //
TR0=1; //
TXD_PIN=0; //发送起始位0
rxdOrTxd=1; //
txdEnd=0; //
}
/**
* 功能:T0中断服务函数,完成接收或发送数据的处理。
* 参数:无
**/
void timer0() interrupt 1
{
static unsigned char cnt=0;
if (rxdOrTxd) //发送
{
cnt++; //
if (cnt <=8)
{
TXD_PIN =txdBuf & 0x01;
txdBuf >>= 1;
}
else if (cnt == 9)
{
TXD_PIN=1;
}
else
{
TR0=0;
ET0=0;
cnt=0;
txdEnd=1;
}
}
else //处理接收
{
if (cnt==0)
{
if (RXD_PIN)
{
TR0=0;
}
else
{
rxdBuf=0;
cnt++;
}
}
else if (cnt <=8)
{
rxdBuf >>=1;
if(RXD_PIN)
{
rxdBuf |= 0x80;
}
cnt++;
}
else
{
TR0=0;
cnt=0;
if (RXD_PIN)
{
rxdEnd=1;
}
}
}
}
2.串口演示例程
体验指针和 sizeof()的用法。例程首先接收上位机下发的命令,根据命令值分别把不同数组的数据回发给上位机。在上位机串口调试助手中分别下发 1、2、3、4,就会得到不同的数组回发,注意这里都用十六进制发送和十六进制显示
#include <reg52.h>
bit cmdArrived=0; //
unsigned char cmdIndex=0; //
unsigned char cntTxd=0; //
unsigned char *ptrTxd; //
unsigned char a1[1]={1};
unsigned char a2[2]={1,2};
unsigned char a3[4]={1,2,3,4};
unsigned char a4[8]={1,2,3,4,5,6,7,8};
void configUART(unsigned int baud);
void main()
{
EA=1;
configUART(4800);
while(1)
{
if (cmdArrived)
{
cmdArrived=0;
switch(cmdIndex)
{
case(1): ptrTxd = a1; cntTxd=sizeof(a1);TI=1;break;
case(2): ptrTxd = a2; cntTxd=sizeof(a2);TI=1;break;
case(3): ptrTxd = a3; cntTxd=sizeof(a3);TI=1;break;
case(4): ptrTxd = a4; cntTxd=sizeof(a4);TI=1;break;
default: break;
}
}
}
}
/**
* 名称:configUART
* 功能:T1中断配置函数
* 参数:baud——串口波特率
**/
void configUART(unsigned int baud)
{
unsigned int tmp;
SCON=0X50; //配置串口为模式1
TMOD &=0X0F; //
TMOD |=0x20;
tmp=12000000/12/2/16/baud; //
TH1=256-tmp;
TL1=TH0; //
ET1=0;
ES=1; //使能串口中断
TR1=1;
}
/**
* 功能:串口中断服务函数,完成接收或发送数据的处理。
* 参数:无
**/
void UART() interrupt 4
{
if(RI)
{
RI=0;
cmdIndex=SBUF;
cmdArrived=1;
}
if (TI)
{
TI=0;
if (cntTxd>0)
{
SBUF=*ptrTxd;
cntTxd=0;
ptrTxd++;
}
}
}
第12章 指针基础与1602认识
sizeof()
操作,相当于一个常量,因它是在程序编译的时候进行的,sizeof()括号中可以是变量名,也可以是变量类型名
- 常量:直接常量与符号常量
符号常量声明的两种方式:
: const 类型 符号常量名字 = 常量值;
: #define 符号常量名 常量值
字符型常量有两种,普通字符和转义字符
字符串常量在内存中按顺序逐个存储字符串中的字符的ASCII码值,最后有一个字符’\0’
单片机读外部状态前,必须先保证自己是高电平
1602操作时序
#define LCD1602_DB P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
- 读状态:RS=L, R/W=H, E=H;
LCD1602_DB = 0XFF;
LCD1602_RS=0;
LCD1602_RW=1;
LCD1602_E=1;
sta = LCD1602_DB;
如果1602设备处于忙的状态,需要等待;由于P0总线被多个设备共用,因此需及时释放P0总线,避免干扰其它设备的使用。因此改写上面程序:
LCD1602_DB=0xFF;
LCD1602_RS=0;
LCD1602_RW=1;
do {
LCD1602_E=1;
sta=LCD1602_DB;
LCD1602_E=0;
} while(sta & 0x80)
-
读数据:RS=H, R/W=L,E=H;
-
写指令:RS=L, R/W=L, D0~D7=指令码, E=高脉冲;
E=高脉冲的意思就是:E使能引脚先从低拉高,再从高拉低,形成一个高脉冲。 -
写数据:RS=H, R/W=L, D0~D7=指令码, E=高脉冲;
版权声明:本文为CSDN博主「acktomas」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/acktomas/article/details/104655795
暂无评论