目录
【1】通信的基础知识
【2】USART
【3】串口通信协议
【4】相关寄存器
串口控制寄存器
波特率寄存器
中断和状态寄存器
数据发送寄存器
数据接收寄存器
【5】 USART功能框图
【6】串口发送实验
实验要求
1.观察实物
2.分析原理图
3.STM32CubeMX配置
4、寄存器方式编写发送接受一个字节的函数
5、寄存器方式编写发送接受一个字节的函数
6、串口发送接收函数验证
7、不定长接受
8、重定向
【1】通信的基础知识
1.通信:至少有收发两方
2.通信方式的划分
同步信号:通信双方根据同步信号通信,比如双方有一个共同的时钟信号(SPI同步通信)
异步通信:通信双方有自己的独立系统时钟,大家约定通信的速度,异步通信不需要
同步比异步多了根线,这个线是同步时钟
串行通信:指的是同一时刻只能发送一个bit位,因此只需要一根新也可以
优点:占用引脚资源少
缺点:速率慢
并行通信:指的是同一时刻可以发送或者接收多个bit位,所以需要多根数据线
优点:占用引脚资源多
缺点:速率快
串行通信与并行通信的区别:
串行传输距离远
并行传输距离近
1602LED屏幕就是并行通信
单工、半双工、全双工:
单工:要么收,要么发,只能做接受设备或者发送设备。比如:收音机
半双工:可以收,可以发,但是同一时刻只能收或者发。比如:对讲机
全双工:可以在同一时刻即接收,又发送。手机
485半双工 用差分的方式
UART常用的串口通信
SPI LED屏幕有点SPI支持 ss片选相当于点名 主机相当于老师 从机相当于学生
I2C是单总线加了同步时钟
【2】USART
Universal Synchonous Asynchronous receiver transmitter
中文参考手册 564页
USART: 支持同步\异步通信、全双工、串行
UART :没有信号线,只支持异步通信、全双工、串行
USART不配置时钟线实现UART
【3】串口通信协议
数据帧格式:
空闲状态:信号线保持高电平
起始位:1位 低电平表示数据包的起始
数据位:8位or9位
校验位(可选):奇偶校验
奇校验:
数据位上的1的个数 + 校验位上1的个数 = 奇数
偶校验:
数据位上的1的个数 + 校验位上1的个数 = 偶数
停止位:1位 将电平信号拉高,代表一个数据包发送结束,回到空闲状态。
波特率:
【4】相关寄存器
串口控制寄存器
(设备功能初始化、通信帧格式配置)
USART_CR1 USART_CR2 USART_CR3
波特率寄存器
USART_BRR
中断和状态寄存器
USART_ISR
数据发送寄存器
USART_TDR
数据接收寄存器
USART_RDR
TDR与RDR 数据发收寄存器
数据总线--写---发送数据寄存器--发送位移寄存器--数据发送端
数据接收端---接收位移寄存器---接收数据寄存器---读
时钟线间接与波特率有关
【5】 USART功能框图
Tx:数据发送端
Rx:数据接收端
流控概念
在两个设备正常通信时,由于处理速度不同,就存在这样一个问题,有的快,有的慢,在某些情况下,就可能导致丢失数据的情况。如台式机与单片机之间的通讯,接收端数据缓冲区已满,则此时继续发送来的数据就会丢失。流控制能解决这个问题
nRTS:请求以发送(Request To Send),n表示低电平有效。当本设备准备好接收新数据时就会将nRTS变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。
nCTS:清除以发送(Clear To Send) 为输入信号,低电平有效。用于判断是否可以向对方发送数据,低电平说明本设备可以向对方发送数据。
该引脚只适用于硬件流控制
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
发送过程:由CPU和DMA向数据发送寄存器(TDR)中写入要发送的数据,由发送移位寄存器将数据按位移到发送端口输出。
接收过程:由CPU和DMA读取接收数据寄存器(RDR)中的数据。
【6】串口发送实验
实验要求
通过单片机向电脑(串口助手)发送数据
1.观察实物
找到通信接口 丝印“P4”
2.分析原理图
CH340 : 电平转换芯片,可以转换TTL电平-USB电平。
数据选择器/多路复用器
3.STM32CubeMX配置
4、寄存器方式编写发送接受一个字节的函数
//写一个单字节发送的函数
void put(uint8_t ch)
{
while(!(USART1->ISR & 1<<7)){}
//判断发送数据寄存器是不是空了
USART1->TDR=ch;
//将数据写入到TDR寄存器中
}
int get()
{
uint8_t ch;
while(!(USART1->ISR & 1<<5)){}
//判断接受数据寄存器是不是空了
ch=USART1->RDR;
//将数据从RDR寄存器中读出来
return ch;
}
5、寄存器方式编写发送接受一个字节的函数
HAL_UART_Transmit(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size,
uint32_t Timeout)
功能:串口发送数据
参数:huart ->串口选择(USART1)
pData ->需要发送的数据
Size->发送多少个数据
Timeout->超时时间
返回值:成功返回HAL_OK 失败返回HAL_TIMEOUT
HAL_UART_Receive(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
功能:串口接受数据函数
参数:
huart ->串口选择(USART1)
pData ->接收数据的地址
Size->发送多少个数据
Timeout->超时时间
返回值:成功返回HAL_OK 失败返回HAL_TIMEOUT
6、串口发送接收函数验证
HAL_UART_Receive(&huart1,buf,2,100);
HAL_UART_Transmit(&huart1,buf,strlen(buf),100);
memset(buf,0,sizeof(buf));
7、不定长接受
声明
uint8_t buf[128]={"0 "};//数据缓存区
uint8_t byte;//单个字节缓存区
uint8_t len=0;//接收到的数据长度
写在while内
if(HAL_UART_Receive(&huart1,&byte,1,100)==HAL_OK)
//判断接收一个字节是否成功
{
if(byte=='\n')//判断是否结束
{//如果结束处理数据
HAL_UART_Transmit(&huart1,buf,len,100);//原封不动回回去
memset(buf,0,len);//清空缓存区
len=0; //长度清0
}
else//如果没有接收完成
{
buf[len++]=byte;//继续接收,把接收到的数据存储到buf
}
}
8、重定向
//printf的重定向
int fputc(int ch,FILE *f)
{
while(!(USART1->ISR & 1<<7)){}
//判断发送数据寄存器是不是空了
USART1->TDR=ch;
//将数据写入到TDR寄存器中
}
//scanf的重定向
int fgetc(FILE *f)
{
uint8_t ch;
while(!(USART1->ISR & 1<<5)){}
//判断接受数据寄存器是不是空了
ch=USART1->RDR;
//将数据从RDR寄存器中读出来
return ch;
}
scanf("%s",buf);
printf("%s",buf);
HAL_Delay(500);