[其他ST产品] USART串口发送&串口发送+接收代码

[复制链接]
2411|18
 楼主| 4c1l 发表于 2023-7-25 17:55 | 显示全部楼层 |阅读模式
1.程序初始化流程

1)开启USART和GPIO时钟。

2)GPIO初始化,把TX配置成复用输出,RX配置成输入。

3)使用结构体配置USART。

如果只需发送功能,直接开启USART就行了。

如果需要发送和接收,需要在开启USART之前加上ITConfig和NVIC的代码。

初始化完成,只需调用特定函数就能完成发送和接收。要获取发送和接收的状态,调用获取标志位函数。

2787464bf9c16644aa.png
 楼主| 4c1l 发表于 2023-7-25 17:56 | 显示全部楼层
2.USART常用函数

  1. void USART_DeInit(USART_TypeDef* USARTx);

  2. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

  3. void USART_StructInit(USART_InitTypeDef* USART_InitStruct);

  4. void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
  5. void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);
  6. //配置同步时钟输出,包括时钟是不是要输出,时钟的极性相位等

  7. void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

  8. void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

  9. void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);
  10. 开启USART到DMA的触发通道

  11. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
  12. //发送数据(写DR寄存器)

  13. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
  14. //接收数据(读DR寄存器)DR寄存器内部有4个寄存器控制发送和接收

  15. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
  16. void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
  17. ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
  18. void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
  19. //标志位相关函数
 楼主| 4c1l 发表于 2023-7-25 17:56 | 显示全部楼层
串口初始化
  1. void Serial_Init()
  2. {
  3.         //开启时钟
  4.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
  5.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  6.        
  7.         //定义引脚
  8.         GPIO_InitTypeDef GPIO_InitStructure;
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX用复用推挽输出,RX用输入模式 一般用
  10.     //浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
  11.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  14.        
  15.         //初始化USART
  16.         USART_InitTypeDef USART_InitStructure;
  17.         USART_InitStructure.USART_BaudRate  = 9600 ;//配置波特率
  18.         USART_InitStructure.USART_HardwareFlowControl  = USART_HardwareFlowControl_None ;
  19.     //硬件流控制 ,内容有不使用流控,只用CTS,只用RTS,或CTS,RTS都使用
  20.         USART_InitStructure.USART_Mode  = USART_Mode_Tx ;
  21.     //发送模式  ( USART_Mode_Tx|USART_Mode_Rx)发送和接收模式
  22.         USART_InitStructure.USART_Parity  = USART_Parity_No ;// 校验位  无校验
  23.         USART_InitStructure.USART_StopBits  = USART_StopBits_1 ;//停止位  选1位
  24.         USART_InitStructure.USART_WordLength  = USART_WordLength_8b ;//字长  8位
  25.         USART_Init(USART1, &USART_InitStructure);

  26.     USART_Cmd(USART1, ENABLE);
  27. }
 楼主| 4c1l 发表于 2023-7-25 17:56 | 显示全部楼层
USARTFA发送数据函数
  1. void Serial_SendByte(uint8_t Byte)
  2. {
  3.         USART_SendData(USART1, Byte);
  4. //函数执行内容:Byte把数据传给Data,之后Data&01FF,即把无关的高位清零,然后赋值给DR寄存器
  5.         while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) ;
  6. //等待TXE置1 ,当数据从TDR寄存器转到发送位移寄存器时TXE才会置1
  7.         //不需要手动清零

  8. }
 楼主| 4c1l 发表于 2023-7-25 20:31 | 显示全部楼层
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Transmits single data through the USARTx peripheral.
  3.   * @param  USARTx: Select the USART or the UART peripheral.
  4.   *   This parameter can be one of the following values:
  5.   *   USART1, USART2, USART3, UART4 or UART5.
  6.   * @param  Data: the data to transmit.
  7.   * @retval None
  8.   */
  9. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
  10. {
  11.   /* Check the parameters */
  12.   assert_param(IS_USART_ALL_PERIPH(USARTx));
  13.   assert_param(IS_USART_DATA(Data));
  14.    
  15.   /* Transmit Data */
  16.   USARTx->DR = (Data & (uint16_t)0x01FF);
  17. }
 楼主| 4c1l 发表于 2023-7-25 20:32 | 显示全部楼层
主函数
  1. int main(void)
  2. {
  3.         OLED_Init();
  4.         Serial_Init();
  5.        
  6.         Serial_SendByte(0x41);
  7.         //上电后,初始化串口,在调用串口发送0x41,TX引脚就会产生0X41的波形
  8.         //这个波形可以发送给其他USB转串口的模块发送到电脑端

  9.        
  10.         while (1)
  11.         {
  12.                
  13.         }
  14. }
 楼主| 4c1l 发表于 2023-7-25 20:32 | 显示全部楼层
串口接收,可以使用中断和查询两种方法

如果使用查询,初始化就结束了,使用中断需要开启中断,配置NVIC

查询的流程:

1)在主函数里不断判断RXNE标志位,如果置1就说明接收数据了

2)调用ReceiveData,读取DR寄存器
 楼主| 4c1l 发表于 2023-7-25 20:32 | 显示全部楼层
中断的流程:

串口配置代码
  1. #include "stm32f10x.h"                  // Device header
  2. #include "stdio.h"
  3. #include "stdarg.h"

  4. uint8_t Serial_RxData;
  5. uint8_t Serial_RxFlag;

  6. void Serial_Init(void)
  7. {
  8.         //开启时钟
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
  10.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  11.        
  12.         //定义引脚
  13.         GPIO_InitTypeDef GPIO_InitStructure;
  14.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX用复用推挽输出,RX用输入模式 一般用浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;//接收复用再PA10
  16.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  18.        
  19.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //TX用复用推挽输出,RX用输入模式 一般用浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
  20.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;//接收复用再PA10
  21.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  23.        
  24.         //初始化USART
  25.         USART_InitTypeDef USART_InitStructure;
  26.         USART_InitStructure.USART_BaudRate  = 9600 ;//配置波特率
  27.         USART_InitStructure.USART_HardwareFlowControl  = USART_HardwareFlowControl_None ;//硬件流控制 ,内容有不使用流控,只用CTS,只用RTS,或CTS,RTS都使用
  28.         USART_InitStructure.USART_Mode  = USART_Mode_Tx | USART_Mode_Rx;//发送模式  ( USART_Mode_Tx|USART_Mode_Rx)发送和接收模式
  29.         USART_InitStructure.USART_Parity  = USART_Parity_No ;// 校验位  无校验
  30.         USART_InitStructure.USART_StopBits  = USART_StopBits_1 ;//停止位  选1位
  31.         USART_InitStructure.USART_WordLength  = USART_WordLength_8b ;//字长  8位
  32.         USART_Init(USART1, &USART_InitStructure);

  33.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,
  34. //        USART的RXNE标志位一旦置1,就会向NVIC申请中断,之后就可以在中断函数接收数据

  35.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断优先级分组为2
  36.        
  37.         NVIC_InitTypeDef NVIC_InitStructure;
  38.         NVIC_InitStructure.NVIC_IRQChannel  = USART1_IRQn;
  39.         NVIC_InitStructure.NVIC_IRQChannelCmd  = ENABLE ;
  40.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 1 ;//优先级随便给
  41.         NVIC_InitStructure.NVIC_IRQChannelSubPriority  =1 ;
  42.         NVIC_Init(&NVIC_InitStructure);
  43.        
  44.         USART_Cmd(USART1, ENABLE);
  45. }


  46. //发送字节函数
  47. void Serial_SendByte(uint8_t Byte)
  48. {
  49.         USART_SendData(USART1, Byte);
  50.         //函数执行内容:Byte把数据传给Data,之后Data&01FF,即把无关的高位清零,然后赋值给DR寄存器
  51.        
  52.         while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) ;
  53.         //等待TXE置1 ,当数据从TDR寄存器转到发送位移寄存器时TXE才会置1
  54.         //不需要手动清零

  55. }

  56. void Serial_SendArray(uint8_t *Array, uint16_t Length)//发送一个数组  Length用于判断数组是否结束
  57. {
  58.         uint16_t i;
  59.         for (i=0; i<Length; i++)
  60.         {
  61.                 Serial_SendByte(Array[i]);
  62.         }
  63. }

  64. //发送字符串,由于字符串自带结束位,所以不需要定义长度
  65. void Serial_SendString(char*String)
  66. {
  67.         uint16_t i;
  68.        
  69.         //这里的0对应空字符,是字符串结束标志位
  70.         for (i=0; String[i] != '\0'; i++)
  71.         {
  72.                 Serial_SendByte(String[i]);
  73.         }

  74. }

  75. //次方函数,函数的返回值=X^Y
  76. uint32_t Serial_Pow(uint32_t X, uint32_t Y)
  77. {
  78.         uint32_t Result = 1;
  79.         while (Y--)
  80.         {
  81.                 Result*=X;
  82.         }
  83.         return Result;
  84. }

  85. //函数里需要把Number的,个位十位,百位等 以十进制拆分开,然后转换成字符,数字对应的数据,以此发送出去
  86. //例如 12345 取万位就是12345/10000%10 = 1
  87. //取千位就是12345/1000=12 再%10 =2 百位十位同理
  88. void Serial_SendNumber(uint32_t Number, uint8_t Length)
  89. {
  90.         uint8_t i;
  91.        
  92.         //假设Length为2,第一次循环2-0-1=1,10^1,就是发送10位,第二次循环2-1-1=0,10^0,就是发送个位
  93.         for (i = 0; i < Length; i ++ )
  94.         {
  95.                 Serial_SendByte(Number / Serial_Pow(10 ,Length - i -1) % 10 +0x30);  //加上0x30的原因是字符0对应的ASCLL码表是0X30,也可以加上  '0'
  96.         }
  97.        
  98. }

  99. //使用printf打印
  100. //重定向fputc函数,这个函数是printf的底层 ,printf调用的函数
  101. //这里把fputc重定向到了串口
  102. int fputc(int ch, FILE *f)
  103. {
  104.         Serial_SendByte(ch);
  105.        
  106.         return ch;
  107. }

  108. //*format 用来接收格式化字符串
  109. //...用来接收可变参数列表
  110. //可变参数用法
  111. void Serial_Printf(char*format , ...)
  112. {
  113.         char String[100];
  114.         va_list arg;//va_list是类型名,arg是变量名
  115.         va_start(arg,format);//从format位置开始接收参数表,放在ARG里面
  116.         vsprintf(String,format,arg);//打印位置是String,格式化字符串是format,参数表是arg   sprintf用于接收直接写的参数,封装要用vsprintf
  117.         va_end(arg);//释放参数表
  118.         Serial_SendString(String);//把String发送出去
  119.        
  120. }
  121.        
  122. //中断接收和变量的封装
  123. uint8_t Serial_GetRxFlag(void)
  124. {
  125.         //读完数据后自动清除
  126.         if (Serial_RxFlag == 1 )
  127.         {
  128.                 Serial_RxFlag =0;
  129.                 return 1;//返回1
  130.         }
  131.         return 0;//否则返回0
  132. }

  133. //中断接收和变量的封装
  134. uint8_t Serial_GetRxData(void)
  135. {
  136.         return Serial_RxData;
  137. }

  138. //把数据进行了一次转存,最终还是要扫描查询RxFlag接受数据,对单字节意义不大
  139. void USART1_IRQHandler(void)
  140. {
  141.         //如果RXNE确实置1了就进if,如果读取了DR,接可以自动清除标志位,不用手动清除
  142.         if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  143.         {
  144.                 Serial_RxData = USART_ReceiveData(USART1);//接收数据
  145.                 Serial_RxFlag = 1; //读完数据后置1
  146.                 USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除中断标志位
  147.         }
  148. }
 楼主| 4c1l 发表于 2023-7-25 20:33 | 显示全部楼层
主函数代码:
  1. #include "stm32f10x.h"                  // Device header
  2. #include "Delay.h"
  3. #include "OLED.h"
  4. #include "Serial.h"

  5. uint8_t RxData;

  6. int main(void)
  7. {
  8.         OLED_Init();
  9.         OLED_ShowString(1,1,"RxData:");
  10.         Serial_Init();
  11.        
  12.         while (1)
  13.         {
  14.                 if (Serial_GetRxFlag() == 1) //if成立说明收到数据了
  15.                 {
  16.                         RxData=Serial_GetRxData();//目前接收到的一个字节数据已经在RxData里了
  17.                         Serial_SendByte(RxData);//把接收到的数据回传到电脑
  18.                         OLED_ShowHexNum(1,8,RxData,2);
  19.                
  20.                 }
  21.         }
  22. }
万图 发表于 2023-12-29 07:12 | 显示全部楼层

含有延展到远高于基本开关频率的谐波
Uriah 发表于 2023-12-29 08:15 | 显示全部楼层

这些引线越窄越好
帛灿灿 发表于 2023-12-29 10:11 | 显示全部楼层

输入电容主要是起到高频能量存储器的作用
Bblythe 发表于 2023-12-29 11:14 | 显示全部楼层

输入滤波电容的公共端应作为其他交流电流地的唯一接点
周半梅 发表于 2023-12-29 13:10 | 显示全部楼层

它们对PCB布局的重要性
Pulitzer 发表于 2023-12-29 14:13 | 显示全部楼层

混淆的话,会引起电源工作不稳定
童雨竹 发表于 2023-12-29 16:09 | 显示全部楼层

把这干扰信号再次辐射出去
Wordsworth 发表于 2023-12-29 17:12 | 显示全部楼层

对变换器效率测量
Clyde011 发表于 2023-12-29 18:15 | 显示全部楼层

把纹波电流分摊到每个电容上
公羊子丹 发表于 2023-12-29 19:08 | 显示全部楼层

印制电路板(PCB)的线路设计
您需要登录后才可以回帖 登录 | 注册

本版积分规则

64

主题

702

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部