串口相关知识点
串口通信
串口接线方式
RXD:数据输入引脚,数据接受,STC89系列对应P3.0口
TXD:数据发送引脚,数据发送,STC89系列对应P3.1口
两块芯片的RX TX要交叉接线
串口编程要素
输入/输出数据缓冲
器都叫做SBUF,都用99H地址码,但是是两个独立的8位寄存器
接受数据时char data = SBUF; 发送数据时SBUF = data;
UART是异步串行接口,通信双方使用的时钟不同,因为双方硬件配置不同,因此需要约定好通信速度,即波特率。
利用串口进行编程初体验
写一个函数,要求实现每隔一秒向串口SBUF写入一个数据a
首先利用软件生成波特率初始化代码,再生成软件延时1s的代码,向SBUF发送数据即SBUF = data;代码如下:
#include "reg52.h"
#include <intrins.h>
sfr AUXR = 0x8E;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR &= 0xBF; //定时器1时钟为Fosc/12,即12T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void main()
{
char data_msg = 'a';
//配置C51串口的通信方式
UartInit();
while(1){
Delay1000ms();
//往发送缓冲区写入数据,就完成数据的发送
SBUF = data_msg;
}
}
即可实现要求.
接下去对串口的初始化的代码进行解读。
SBUF 串行口数据缓冲寄存器
实际是2个缓冲器,写SBUF:SBUF = data;读SBUF:data = SBUF;两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器。
PCON 电源控制寄存器
当SMOD=0,串口方式1,2,3时波特率正常
当SMOD=1,串口方式1,2,3时波特率加倍
上述代码初始化中PCON &= 0x7F; //波特率不倍速
将7F展开为二进制0111 1111,PCON与上7F即第一位清零其他位不变,即SMOD置0,波特率不加倍
不配置时默认值为00x1 0000 满足我们的要求SMOD=0;因此无需配置
SCON 串行控制寄存器
我们使用方式1,SM0=0,SM1=1因此SCON配置为0x40;
SMO和SM1
通过配置SM0和SM1口来调整工作方式
方式1和3都涉及定时器的溢出率因此波特率可变,方式0和2波特率不可变
SM2
涉及多机通信控制位
REN
允许/禁止串行接收控制位,由软件置位REN,当REN=1允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN即REN=0时,禁止接收
代码中SCON = 0x50; //8位数据,可变波特率
展开为2进制为0101 0000对应上表,SM0=0 SM1=1表示为工作方式1(8位UART,波特率可变)REN=1允许串口接收状态
TI,RI
TI是发送中断标志位,RI是接收中断标志位
配置定时器 TMOD
另外代码中也对定时器进行了初始化 TMOD &= 0x0F;与0F相与,清空前4位保留后4位;
TMOD |= 0x20;与20(0010 0000)相或,配置定时器1的M1 M2为10,8位自动重装载定时器
可以观察到RX CONTROL和TX CONTROL是由定时器1控制的,因此需要配置定时器1
之后我们针对9600波特率计算出TH1的值
SMOD定义为0,因此得出公式
之后计算出TH1=253转换为二进制为0xFD,因为采取8位自动重载定时器,TL1=TH1=0xFD
最终设置TR1=1打开中断即可完成配置。
此时就可以通过串口传送字符,可以封装一个sendByte函数
void sendByte(char data_msg){
SBUF = data_msg;
}
如果想传送字符串,可以再写一个sendString函数结合指针的操作进行传输
void sendString(char* str){
while(*str != '\0'){
sendByte(*str);//传送指针指向的数据
str++;//将指针后移
}
}
如果就这样传送字符串会发生重复传送的错误,这是因为移位操作的运行也是需要时间的,因此我们可以在sendByte函数中,通过TI发送中断的方法进行延时,代码如下:
void sendByte(char data_msg){
SBUF = data_msg;
//当第8位数据发送完毕后,硬件会将TI置1,需要手动复位
while(!TI);//当TI==0时卡在循环中,说明8位数据还没有传送完毕
TI=0;//软件复位
}
上一篇: 2021 年上半年软件设计师早间问答
下一篇: 学习 Unity3d:将事件绑定到按钮
推荐阅读
-
推荐多个嵌入式软硬件相关公众号
-
使用 namp 验证 SSL/TSL 相关漏洞 CVE-2015-2808,CVE-2013-2566,CVE-2014-3566,CVE-2016-2183,CVE-2015-4000,Transient Diffie-Hellman public key too weak 等。
-
软件设计师】历年真题--模糊知识点备忘录--15年晨题
-
15C++ 结构基础知识点(二)
-
串口相关知识点
-
Linux JVM 相关命令和案例研究
-
音频处理] WAV 文件格式分析(逐字节标题解析 | 相关字段的计算公式)
-
音频知识点 (9) - MP3 是编码格式还是封装格式?
-
[音频] 音频文件格式和相关参数
-
论评估大型视觉语言模型的对抗鲁棒性 - 论文翻译-2 相关工作