关于嵌入式学习——嵌入式硬件3
一、概念
- UART:Universal Asynchronous Receiver/Transmitter 通用异步收发器,硬件通信的形式
- 51有两个串口(1个串口被用于ISP下载程序,1个串口被用于和主机之间的通信)
- 串口通信有两个数据传输线 (TXD)发送信号线/(RXD)接收信号线
二、通信方式
1.单工:
- 发送方和接收方是固定的,数据只能从发送方发给接收方
- 通过一根信号线进行数据传输,数据传输的方向呈现单一性
2半双工:(I2C)
- 通信的双方既可以作为发送方也可以作为接收方
- 数据传输通过一根信号线实现,数据的传输方向可以是双向的
- 同一时刻,数据传输方向呈现单一性(A给B发的时候,B不能给A发,B只能接收数据)
3全双工(UART)
- 通信双方既可以作为发送方也可以作为接收方
- 数据传输是通过两根信号线实现,数据传输在任意时刻都是双向的(收发可以同时进行)
三、数据传输的顺序:
Uart在传输数据时,遵循LSB优先原则(低位先行),先发低位数据,一个bit一个bit发
四、数据传输的形式:
串行:通过一根信号线传输数据,按照先后次序逐个bit逐个bit去发送数据
并行:同时多根信号线同时去传输数据
五、串行传输和并行传输的区别:
串行:
- 传输速率慢(只能通过一根线逐个bit去传输)
- 硬件成本低,实现简单
- 传输距离远,抗干扰性好(RS485 差分)
并行:
- 传输速率快(可以通过多根线同时传输多个bit)
- 硬件成本高,实现复杂
- 传输距离近,抗干扰性差(30米以内 距离增加后多根信号新存在信号偏移,会电磁波干扰,会造成误差和干扰)
六、串口通信时序:
1.串口通信时,空闲状态为高电平
2.当由高电平变为低电平(发送一个低电平信号),代表发送了一个起始位,准备开始通信
3.发送数据(通常是8bit,遵循先发数据低位LSB原则)
4.再发送一个bit的校验位
tip:
校验:
奇偶校验(串口)
累加和校验
CRC校验(Modbus协议)
七、奇偶校验:
问题:无法检测偶数个bit出错
- 奇校验:校验位为1,若数据位中1的个数加上校验位中的1,保持1的个数为奇数个,则代表校验通过
- 偶校验:校验位为0,若数据位中1的个数加上校验位中的0,保持1的个数为偶数个,则代表校验通过
八、串口通信参数(波特率、数据位、停止位、校验位):
波特率:bps(bit per second),每秒钟传输bit的数量,常见的波特率:2400,4800,9600,115200
数据位:8位串口传输通常8bit数据位传输
停止位:1,1bit停止位
校验位:
- None,N,无校验
- Even,E,偶校验
- Odd,O,奇校验
ex:
9600, 8, N, 1
2400,8,E,1
115200, 8, 0, 1
九、同步通信和异步通信
UART、I2C、SPI?同步?异步?
I2C(SCL:时钟线,SDA:数据线)
SPI(SCLK时钟线)
UART(无时钟线)
同步:通信的双方有一根共享的时钟线来约定通信的频率(同步发送数据/接收数据)
异步:通信双方没有时钟线进行同步,如Uart:可以通过设置波特率来实现同步(发:2400bps收:2400bps)
十、串口相关寄存器:
(1)SCON/PCON串口控制寄存器:
- PCON寄存器中的bit6置0代表通过SCON寄存器中SMO和SM1两位指定串口工作方式:
- 将SCON寄存器中的bit6和bit7清0
- 将SCON寄存器中的SM1 bit6置1,SM0bit7清0,代表串口工作8位UART模式
- 将SCON寄存器中REN bit4置1,代表允许串口接收数据
- SCON寄存器中bit1 T1位,代表串口8位数据发送完毕硬件自动置1,但需要软件清0(查询)
- SCON寄存器bit0 R1位,代表串口8位数据接收完毕硬件自动置1,但需要软件清0(查询)
- PCON寄存器bit7位置1,代表波特率加倍
(2)串口数据缓冲寄存器SBUF:无需配置,数据传入即可:
有2个互相独立的接收、发送缓冲器,可以同时发送和接收数据。发送缓冲器只能写入而不能读出,接收缓冲器只能读出而不能写入,因而两个缓冲器可以共用一个地址码(99H)。两个缓冲器统称串行通信特殊功能寄存器SBUF。
(3)定时器相关配置:
1. 串口为什么需要定时器?
UART 是异步通信,没有单独的时钟线,收发双方必须事先约定一个比特时间(波特率)。
单片机内部通常没有“波特率发生器”专用模块,于是把定时器借过来当波特率发生器用。
定时器以固定频率溢出(或翻转),每溢出一次就产生一个“tick”给 UART,告诉它:“该发/收 1 位数据了”。
TMOD定时器模式选择寄存器:
- 将TMOD寄存器中的高四位清0(定时器1)
- 将TMOD寄存器中的bit5置1,bit4清0,代表定时器1工作在8位自动重装载模式
- 将TCON寄存器中的bit6置1,代表允许定时器1开始计数
定时器初值的计算公式:
公式:2^8-2^smod * focs / 32 / bps / 12
其中smod表示PCON的B7,根据实际情况带入,不是0就是1(波特率是否加倍);
focs晶振频率,我是12Mhz = 12000000hz;
bps目标波特率 我是2400bps
2^8这里的8来自定时器的工作方式,因为我使用的是8位自动重装方式,所以是8
按要求2400bps,smod=1时,该公式计算结果为:230
(4)中断寄存器相关配置:
为什么需要中断寄存器?如果没有,定时器溢出之后也不会有中断产生呀
IE中断控制寄存器:
- 将IE寄存器中的bit7 EA位 置1,代表CPU能够响应所有中断
- 将IE寄存器中的bit4 ES位 置1,代表允许串口产生中断
//串口初始化
void Uart_Init(void)
{
//串口控制寄存器配置PCON &= ~(1 << 6);//CON寄存器中的bit6置0 代表通过SCON寄存器中SMO和SM1两位指定串口工作方式SCON &= ~(3 << 6);//将SCON寄存器中的bit6和bit7清0SCON |= (1 << 6);//将SCON寄存器中的SM1bit6置1,M0bit7清0(前一步已清),表串口工作8位UART模式SCON |= (1 << 4);//将SCON寄存器中RENbit4置1,代表允许串口接收数据PCON |= (1 << 7);//CON寄存器bit7位置1,代表波特率加倍//定时器和中断寄存器相关配置初始化 (定时器1 8位自动重装载模式)//定时器1TMOD &= ~(0xF0 << 0);//将TMOD寄存器中的高四位清0(定时器1)TMOD |= (1 << 5);//TMOD寄存器中的bit5置1,bit4清0(前一步已清),代表定时器1工作在8位自动重装载模式//计算起始点: 2^8-2^smod *focs / 32 / bps / 12Tl1 = 230;TH1 = 230;TCON |= (1 << 6);//将TCON寄存器中的bit6置1,代表允许定时器1开始计数//定时器中断IE |= (1 << 7);//总开关 将IE寄存器中的bit7EA位置1,代表CPU能够响应所有中断IE |= (1 << 4);//允许定时器1产生中断 将IE寄存器中的bit4 ES位置1,代表允许串口产生中断return;
}
十一 、串口中断服务函数——传递字符、传递字符串、传递数组
while (1){
// Uart_SendChar('y');
// Uart_SendStr("Hello world!");Uart_SendBuffer(buffer, strlen(buffer));//向串口发送数组里的内容delay(0x3FFF);}}#include <reg51.h>xdata char recv_buffer[32];
unsigned int pos = 0;
//串口接收服务函数
void Uart_RecvHandler(void) interrupt 4
{if((SCON & (1 << 0)) == 1)//成功接收到8位数据 根据SCON bit0判断是否接收到{if (pos < 32){recv_buffer[pos++] = SBUF;//一次串口中断 接收到一个字节 存入数组 并把数组下标后移一位 recv_buffer[pos] = 0;//下一个数组下标的元素值清零}SCON &= ~(1 << 0);//SCON bit0 软件置0;}return ;
}//串口初始化
void Uart_Init(void)
{
//串口控制寄存器配置PCON &= ~(1 << 6);//CON寄存器中的bit6置0 代表通过SCON寄存器中SMO和SM1两位指定串口工作方式SCON &= ~(3 << 6);//将SCON寄存器中的bit6和bit7清0SCON |= (1 << 6);//将SCON寄存器中的SM1bit6置1,M0bit7清0(前一步已清),表串口工作8位UART模式SCON |= (1 << 4);//将SCON寄存器中RENbit4置1,代表允许串口接收数据PCON |= (1 << 7);//CON寄存器bit7位置1,代表波特率加倍//定时器和串口中断寄存器相关配置初始化 (定时器1 8位自动重装载模式)//定时器1TMOD &= ~(0xF0 << 0);//将TMOD寄存器中的高四位清0(定时器1)TMOD |= (1 << 5);//TMOD寄存器中的bit5置1,bit4清0(前一步已清),代表定时器1工作在8位自动重装载模式//计算起始点: 2^8-2^smod *focs / 32 / bps / 12TL1 = 230;TH1 = 230;TCON |= (1 << 6);//将TCON寄存器中的bit6置1,代表允许定时器1开始计数IE |= (1 << 7);//总开关 将IE寄存器中的bit7EA位置1,代表CPU能够响应所有中断IE |= (1 << 4);//允许串口产生中断 将IE寄存器中的bit4 ES位置1,代表允许串口产生中断return;
}
//向串口发送字符
void Uart_SendChar(unsigned char buff)
{///tip:SCON寄存器初始上电后 所有位置清零SBUF = buff;//SCON寄存器中bit1 T1位,代表串口8位数据发送完毕硬件自动置1,但需要软件清0(查询)while((SCON & (1 << 1)) == 0);//发送数据完毕后,硬件置1,查询是否发送SCON &= ~(1 << 1); //软件给此位清零return;
}
//向串口发送字符串
void Uart_SendStr(const char *p)
{while(*p){Uart_SendChar(*p++); //等价于*(p++)//1取出当前 p 指向的值(*p)//2把指针 p 向后挪一个元素(p++)}return;
}
//向串口发送数组中的数据
void Uart_SendBuffer(const char *p, int lenth)
{
// int i = 0;
// for(i = 0; i < lenth; i++)
// {
// Uart_SendChar(*p);
// p+=i;
// }while(lenth--){Uart_SendChar(*p++);}return;
}
十二、主从应答:
主机:拥有对通信绝对控制权,通信都是由主机发起
从机:无法直接发起通信,只能根据主机下发的指令完成对应操作
#include <reg51.h>
#include <string.h>
#include "uart.h"
#include "delay.h"int main(void)
{xdata char buffer[32] = {0};Uart_Init(); while (1){
// Uart_SendChar('y');
// Uart_SendStr("Hello world!");
// Uart_SendBuffer(buffer, strlen(buffer));if(pos != 0){
// Uart_SendBuffer(recv_buffer, strlen(recv_buffer));//向串口发送数组里的内容delay(0x3FFF);if(strcmp(recv_buffer,"hello") == 0){Uart_SendStr("Hello world!");}if(strcmp(recv_buffer,"hi") == 0){Uart_SendStr("Hi world!");}pos = 0;}}return 0;
}
十二、Modbus协议:
Modbus协议
(主机 - >从机)
起始位 地址码 功能码 数据位1 数据位2 校验码 停止位
0xAA 0x01 0x01 00 42 EE(累加和校验) 0xBB
(从机->主机)
起始位 地址码 功能码 数据位1 数据位2 校验码 停止位
0xAA 0x01 0x81 00 42 6E 0xBB
累加和校验:前五个之和等于校验码
功能码:bit7:数据流向位 0“表示从主机流向从机 / 1表示从从机流向主机
bit0: 1:控制LED灯
2:控制数码管(动态显示)
3:控制 蜂鸣器(频率)
4::温度采集
总结重点:
一、主机发送指令,从机解析主机发送的指令并获得功能码,根据功能码完成对外设的控制,并回复应答给主机
(01 --- LED控制 02 --- 数码管控制 03 --- 蜂鸣器控制)
二、
1.UART的概念
2、单工、半双工、全双工概念
3、串行、并行概念
4、串行、并行区别
5、 串口通信时序
6、奇偶校验的概念/缺点
7、串口通信参数(波特率 数据位 停止位 校验位 2400 8 N 1)
8、同步、异步概念
9、主从应答的概念
10、主机、从机