小言_互联网的博客

02 USART

280人阅读  评论(0)

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。

单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。

每一种通讯协议都有硬件与软件上的要求。

硬件协议

  • 简单双向串口通信有两根通信线(发送端TX和接收端RX)
  • TX与RX要交叉连接
  • 当只需单向的数据传输时,可以只接一根通信线
  • 当电平标准不一致时,需要加电平转换芯片

软件协议

串口参数

波特率:串口通信的速率

起始位:标志一个数据帧的开始,固定为低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

校验位:用于数据验证,根据数据位计算得来

停止位:用于数据帧间隔,固定为高电平

串口时序

实例分析:9600波特率,8位数据,无校验位,1位停止

奇偶校验

在前面的8位数据中,保证其高电平1出现的次数位奇数/偶数。

如下示例,偶校验,前面已经有4个1了,所以校验位应该是0.

多数据

就是把单个一个字节时序,往一块拼接。

以32为例分析一下USART

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器。

有时候大家还会见到UART,其实就是把S-Synchronous-同步 去掉了,咱们平时的使用中其实还是异步的UART,很好用到同步功能。USART可以说是UART升级之后带上了同步。

基本框图

看着比较复杂,其实从我们应用上来讲,就三个点:设置发送接收速率、发送、接收

配置串口程序

看注释理解:


  
  1. void Serial_Init( void)
  2. {
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口1时钟
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能串口IO口外设
  5. //GPIO的结构体参数配置
  6. GPIO_InitTypeDef GPIO_InitStructure;
  7. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  9. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  10. GPIO_Init(GPIOA, &GPIO_InitStructure);
  11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //输入上拉
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14. GPIO_Init(GPIOA, &GPIO_InitStructure);
  15. //串口参数配置
  16. USART_InitTypeDef USART_InitStructure;
  17. USART_InitStructure.USART_BaudRate = 9600;
  18. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  19. //不开启硬件流控
  20. USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  21. USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶失能
  22. USART_InitStructure.USART_StopBits = USART_StopBits_1; //1个停止位
  23. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位的数据
  24. USART_Init(USART1, &USART_InitStructure);
  25. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //中断使能
  26. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断向量分组
  27. //中断向量表的相关配置
  28. NVIC_InitTypeDef NVIC_InitStructure;
  29. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  30. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  31. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  32. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  33. NVIC_Init(&NVIC_InitStructure);
  34. USART_Cmd(USART1, ENABLE);
  35. }

之后便是根据自己的需要,同时使用好标准库这个武器库里面的武器,写自己的外设驱动函数,可以发送一个比特位,可以发送一个数组,可以发送一个一个字符串……

当然还有最后的中断函数。


  
  1. void Serial_SendByte(uint8_t Byte)
  2. {
  3. USART_SendData(USART1, Byte);
  4. while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  5. }
  6. void Serial_SendArray(uint8_t *Array, uint16_t Length)
  7. {
  8. uint16_t i;
  9. for (i = 0; i < Length; i ++)
  10. {
  11. Serial_SendByte(Array[i]);
  12. }
  13. }
  14. void Serial_SendString( char *String)
  15. {
  16. uint8_t i;
  17. for (i = 0; String[i] != '\0'; i ++)
  18. {
  19. Serial_SendByte(String[i]);
  20. }
  21. }
  22. uint32_t Serial_Pow(uint32_t X, uint32_t Y)
  23. {
  24. uint32_t Result = 1;
  25. while (Y --)
  26. {
  27. Result *= X;
  28. }
  29. return Result;
  30. }
  31. void Serial_SendNumber(uint32_t Number, uint8_t Length)
  32. {
  33. uint8_t i;
  34. for (i = 0; i < Length; i ++)
  35. {
  36. Serial_SendByte(Number / Serial_Pow( 10, Length - i - 1) % 10 + '0');
  37. }
  38. }
  39. int fputc( int ch, FILE *f)
  40. {
  41. Serial_SendByte(ch);
  42. return ch;
  43. }
  44. void Serial_Printf( char *format, ...)
  45. {
  46. char String[ 100];
  47. va_list arg;
  48. va_start(arg, format);
  49. vsprintf(String, format, arg);
  50. va_end(arg);
  51. Serial_SendString(String);
  52. }
  53. uint8_t Serial_GetRxFlag( void)
  54. {
  55. if (Serial_RxFlag == 1)
  56. {
  57. Serial_RxFlag = 0;
  58. return 1;
  59. }
  60. return 0;
  61. }
  62. uint8_t Serial_GetRxData( void)
  63. {
  64. return Serial_RxData;
  65. }
  66. void USART1_IRQHandler( void)
  67. {
  68. if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  69. {
  70. Serial_RxData = USART_ReceiveData(USART1);
  71. Serial_RxFlag = 1;
  72. USART_ClearITPendingBit(USART1, USART_IT_RXNE);
  73. }
  74. }

硬件流控制是什么?

RTS与CTS

A要发送数据,即Request To Send “请求发送”(数据),B看到RTS有效了,决定,如果自己要做一些准备工作,就设置CTS无效,如果本身准备好了,就设置CTS,Clear To Send,表示对于你的Send发送(数据)来说,我已经Clear(忙清了)。所以A看到CTS有效就可以发送数据了。

然后接下来的每一个从A发送到B的字节数据都是这么个过程。中间有可能遇到说,B的buffer full 缓存满了,所以要设置CTS无效,A发现后,就停止发送数据,继续检测CTS直到有效,才继续发送数据。

正常数据发送完成后,A就把最开始设置为有效的RTS这个标示清除掉,即设置RTS无效,表示数据传完了。 由此,整个A发送数据到B的过程就Over了。


转载:https://blog.csdn.net/weixin_43824188/article/details/128518355
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场