• USART使用


    USART软件配置

    具体步骤如下:(USART 相关库函数在 stm32f10x_usart.c 和 stm32f10x_usart.h 文件中)

    (1)使能串口时钟及 GPIO 端口时钟

    前面说过 STM32F103C8T6 芯片具有 3 个串口,对应不同的引脚,串口 1 挂接在 APB2 总线上,串口 2-串口 3 挂接在 APB1 总线上,根据自己所用串口使能总线时钟和端口时钟。

    例如使用 USART1,其挂接在 APB2 总线上,并且 USART1 对应 STM32 芯片管脚的 PA9 和 PA10,因此使能时钟函数如下:

     
    

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟

    (2)GPIO 端口模式设置,设置串口对应的引脚为复用功能

    因为使用引脚的串口功能,所以在配置 GPIO 时要将设置为复用功能,这里

    把串口的 Tx 引脚配置为复用推挽输出, Rx 引脚为浮空输入,数据完全由外部

    输入决定。如下:

     
    

    GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX //串口输出 PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入 IO */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX //串口输入 PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */

    (3)初始化串口参数,包含波特率、字长、奇偶校验等参数

    要使用串口功能,必须对串口通信相关参数初始化,其库函数如下:

     
    

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

    想必不用说,大家也知道第一个参数是什么意思,它是用来选择串口。

    第二个参数是一个结构体指针变量,结构体类型是 USART_InitTypeDef,

    其内包含了串口初始化的成员变量。下面我们就来看下这个结构体:

     
    

    typedef struct { uint32_t USART_BaudRate; //波特率 uint16_t USART_WordLength; //字长 uint16_t USART_StopBits; //停止位 uint16_t USART_Parity; //校验位 uint16_t USART_Mode; //USART 模式 uint16_t USART_HardwareFlowControl; //硬件流控制 } USART_InitTypeDef;

    USART_BaudRate:

    波特率设置。常用的波特率为 4800、9600、115200 等。

    标准库 函 数 会 根 据 设 定 值 计 算 得 到 USARTDIV 值 , 并 设 置USART_BRR 寄存器值。

    USART_WordLength:

    数据帧字长。可以选择为 8 位或者 9 位,

    通过 USART_CR1 寄存器的 M 位的值决定。如果没有使能奇偶校验控制,一般使用 8 数据位;

    如果使能了奇偶校验则一般设置为 9 数据位。

    USART_StopBits:

    停止位设置。可选 0.5 个、 1 个、 1.5 个和 2 个停止 位,

    它设定 USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。

    通常使用1

    USART_Parity:

    奇偶校验控制选择。可选 USART_Parity_No( 无 校 验 ) 、

    USART_Parity_Even( 偶 校 验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) ,

    它设 定 USART_CR1 寄存器的 PCE 位和 PS 位的值。

    USART_Mode:

    USART 模式选择。

    可以为 USART_Mode_Rx 和 USART_Mode_Tx, 允许使用逻辑或运算选择两个,

    它设定 USART_CR1 寄存器的 RE 位和 TE 位。

    USART_HardwareFlowControl:

    硬件流控制选择。

    只有在硬件流控制模式才 有效,

    可以选择无硬件流 USART_HardwareFlowControl_None、

    RTS 控制USART_HardwareFlowControl_RTS、

    CTS 控制 USART_HardwareFlowControl_CTS、 RTS 和 CTS 控制 USART_HardwareFlowControl_RTS_CTS。 了解结构体成员功能后,就可以进行配置,例如我们配置 USART1,如下:

     
    

    USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate =115200;//波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_No ne;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口 1

    (4)使能串口

    配置好串口后,我们还需要使能它,使能串口库函数如下

    void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

    例如我们要使能 USART1,如下:

     
    

    USART_Cmd(USART1, ENABLE);//使能串口 1

    (5)设置串口中断类型并使能

     
    

    // 第五步:设置串口中断类型并使能 USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断

    (6)设置串口中断优先级,使能串口中断通道

     
    

    // 第六步:设置串口中断优先级,使能串口中断通道 NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应 NVIC_Init(&NVIC_InitStruct);

    (7)编写串口中断服务函数

     
    

    //编写串口中断服务函数 void USART1_IRQHandler(void) { u8 r =0; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) // 接受中断 不等于0 就是RESET { r = USART_ReceiveData(USART1); // 接收数据 if((USART1_RX_STA&0x8000)==0) { if((USART1_RX_STA&0x4000)==1) { if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始 else USART1_RX_STA |= 0x80000;//接收完成了 } else //还没收到0X0D { if(r==0x0d)USART1_RX_STA|=0x4000; // 是否为0d 次高位设置 else { USART_RX_BUF[USART1_RX_STA&0x3fff] = r; USART1_RX_STA++; if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0; //接收数据错误,重新开始接收 } } } } }

    为了确认 USART1 是否发生接收中断,调用了读取串口中断状态标志位函数

    USART_GetITStatus,如果确实产生接收中断事件,那么就会执行 if 内的语句,

    将串口接收到的数据保存在变量 r 内,然后有通过串口发送出去,通过

    USART_GetFlagStatus 函数读取串口状态标志,如果数据发送完成,则退出 while

    循环语句。

    这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组

    USART1_RX_BUF[],一个接收状态变量 USART1_RX_STA 实现对串口数据的接收管

    理。USART1_RX_BUF 的大小由 USART1_REC_LEN 定义,也就是一次接收的数据最

    大不能超过 USART1_REC_LEN 个字节。USART1_RX_STA 是一个接收状态变量,其

    各的定义如下图所示:

    设计思路如下:

    当接收到从电脑发过来的数据,把接收到的数据保存在 USART1_RX_BUF 中,同时在接收状态寄存器(USART1_RX_STA)中计数接收到的有效数据个数,

    当收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待 0X0A 的到来,而如果 0X0A 没有来到,

    则认为这次接收失败,重新开始下一次接收。

    如果顺利接收到 0X0A,则标记 USART1_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,

    而如果迟迟没有收到 0X0D,那么在接收数据超过 USART1_REC_LEN 的时候,则会丢弃前面的数据,重新接收。

    软件设计

    usart.c

    1. #include "usart.h"
    2. u16 USART1_RX_STA =0;
    3. u8 USART_RX_BUF[USART_REC_LEN];
    4. void USART1_Init(u32 bound)
    5. {
    6. GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
    7. USART_InitTypeDef USART_InitStruct;
    8. NVIC_InitTypeDef NVIC_InitStruct;
    9. // 第一步 使能串口时钟及 GPIO 端口时钟
    10. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟
    11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟
    12. /* 配置GPIO的模式和IO口 */
    13. // 第二步 GPIO 端口模式设置,设置串口对应的引脚为复用功能
    14. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //TX //串口输出 PA9
    15. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    16. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
    17. GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入 IO */
    18. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //RX //串口输入 PA10
    19. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
    20. GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */
    21. // 第三步:初始化串口参数,包含波特率、字长、奇偶校验等参数
    22. USART_InitStruct.USART_BaudRate = bound; // 波特率
    23. USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长
    24. USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位
    25. USART_InitStruct.USART_Parity = USART_Parity_No; // 奇偶校验位
    26. USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // 不使用硬件流
    27. USART_InitStruct.USART_Mode =USART_Mode_Rx|USART_Mode_Tx; // //收发模式
    28. USART_Init(USART1,&USART_InitStruct);
    29. // 第四步:使能串口 可以放到最后
    30. USART_Cmd(USART1,ENABLE);
    31. // 第五步:设置串口中断类型并使能
    32. USART_ClearFlag(USART1, USART_FLAG_TC); // 清除中断
    33. USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断
    34. // 第六步:设置串口中断优先级,使能串口中断通道
    35. NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断通道
    36. NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    37. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3; // 抢占
    38. NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; // 响应
    39. NVIC_Init(&NVIC_InitStruct);
    40. }
    41. //编写串口中断服务函数
    42. void USART1_IRQHandler(void)
    43. {
    44. u8 r =0;
    45. if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) // 接受中断 不等于0 就是RESET
    46. {
    47. r = USART_ReceiveData(USART1); // 接收数据
    48. if((USART1_RX_STA&0x8000)==0)
    49. {
    50. if((USART1_RX_STA&0x4000)==1)
    51. {
    52. if(r!=0x0a)USART1_RX_STA = 0; //接收错误,重新开始
    53. else USART1_RX_STA |= 0x80000;//接收完成了
    54. }
    55. else //还没收到0X0D
    56. {
    57. if(r==0x0d)USART1_RX_STA|=0x4000; // 是否为0d 次高位设置
    58. else
    59. {
    60. USART_RX_BUF[USART1_RX_STA&0x3fff] = r;
    61. USART1_RX_STA++;
    62. if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0; //接收数据错误,重新开始接收
    63. }
    64. }
    65. }
    66. }
    67. }

    usart.h

    1. #ifndef _usart_H
    2. #define _usart_H
    3. #include "system.h"
    4. #define USART_REC_LEN 200
    5. extern u8 USART_RX_BUF[USART_REC_LEN];
    6. extern u16 USART1_RX_STA;
    7. void USART1_Init(u32 bound);
    8. #endif

    main.c

    1. #include "system.h"
    2. #include "SysTick.h"
    3. #include "led.h"
    4. #include "usart.h"
    5. int main()
    6. {
    7. u8 i =0;
    8. u16 len;
    9. u16 t=0;
    10. SysTick_Init(72);
    11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    12. LED_Init();
    13. USART1_Init(115200);
    14. while(1)
    15. {
    16. if(USART1_RX_STA&0x8000)
    17. {
    18. len =USART1_RX_STA&0x3fff; //得到此次接收到的数据长度
    19. for(t=0;t<len;t++)
    20. {
    21. USART_SendData(USART1,USART_RX_BUF[t]);
    22. while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET); // 获取标记 SET不等于1
    23. }
    24. USART1_RX_STA = 0;
    25. }
    26. i++;
    27. if(i%10==0)
    28. {
    29. LED0=!LED0;
    30. }
    31. delay_ms(10);
    32. }
    33. }

  • 相关阅读:
    Git 查看提交历史
    IDEA添加Vue文件模板
    Flink安装及简单使用
    C++标准模板(STL)- 类型支持 (属性查询,获取类型的对齐要求)
    基于PID控制的四旋翼飞行器仿真(Matlab代码实现)
    Kubernetes上安装Metrics-Server
    时间序列预测:用电量预测 07 灰色预测算法
    tomcat服务&&tomcat多实例部署
    力扣 1582. 二进制矩阵中的特殊位置
    java jdbc Incorrect string value for column
  • 原文地址:https://blog.csdn.net/m0_68021259/article/details/133884084