STM32自学笔记(五)串口通信

2023-05-16

(想要深入理解就把前面的看下,否则直接看使用总结即可)

usart文件夹

usart 文件夹内包含了 usart.cusart.h两个文件。这两个文件用于串口的初始化和中断接收。代码只针对了串口1,如果要用其他串口需要对代码稍作修改。

usart.c包含了2个函数,在下文分别进行讲解

  void USART1_IRQHandler(void);
  void uart_init(u32 bound);

另外,usart.c中包含了对串口printf的支持代码,若去掉会导致硬件无法启动,不要随意修改。

uart_init函数

逐行分析此函数

  1. 串口1对应GPIOA,使能相应的时钟

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

     

  2. 初始化GPIO端口

    根据串口的工作模式按下表进行配置

    USART引脚模式GPIO配置
    USARTx_TX全双工模式推挽复用输出
     半双工同步模式推挽复用输出
    USARTx_RX全双工模式浮空输入或带上拉输入
     半双工同步模式未用,可作为通用I/O

    所以需要把TX(PA9)设置为推挽复用输出模式,将RX(PA10)设置为浮空输入模式

       //USART1_TX   PA.9     
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;       //PA.9 复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出     
      GPIO_Init(GPIOA, &GPIO_InitStructure);          
      //USART1_RX   PA.10 浮空输入
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;      //PA.10 浮空输入
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);   

     

  3. 中断初始化

    接下来需要对usart1进行中断初始化,设置抢占优先级和响应优先级的值

      //Usart1 NVIC 中断配置 配置     
      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       //串口1
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;      //子优先级 3
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ 通道使能
      NVIC_Init(&NVIC_InitStructure);         //根据指定的参数初始化 NVIC 寄存器

     

  4. 串口初始化

    对串口进行初始化,形式与GPIO初始化类似

      //USART 初始化设置  
      USART_InitStructure.USART_BaudRate = bound;                 //波特率设置;
      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_None; //无硬件数据流控制  
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发
      USART_Init(USART1, &USART_InitStructure);   //初始化串口1

     

  5. 开启串口中断以及使能串口

      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断     
      USART_Cmd(USART1, ENABLE);                    //使能串口

     

至此,uart_init()函数讲解完毕,调用它即可完成串口的初始化,只需输入波特率即可。调用示例如下

  uart_init(115200)                       //开启串口1     波特率:115200

USART1_IRQHandler函数

USART1_IRQHandler()函数是串口 1 的中断响应函数,当串口 1 发生了相应的中 断后,就会跳到该函数执行。中断响应函数名不能自定义,在startup_stm32f10x_hd.s 文件中可以找到。

首先,通过以下函数判断是否接收到中断

 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   

若接收到中断,则读取串口接收到的数据

  Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据 

设计的接受协议如下:

USART_RX_STA对接收到的有效数据进行计数,当收到回车(由两个字节组成:0X0D和0X0A)的第一个字节0X0D时,计数器不再增加,等待0X0A的到来,若没有到来视为接受失败,重新开始下一次接收。若顺利接收到0X0A,则标记其第15位完成一次接收,等待该位被其他程序清除,以开始下一次接收。

若一直没有接收到0X0D,数据长度超过 USART_REC_LEN 时,丢弃数据,重新接收。

效果:若数据以回车作为结束在,则接收成功,保存在数组 USART_RX_BUF[]

中断相应函数如下:

 void USART1_IRQHandler(void)                 //串口 1 中断服务程序  
  {  
      u8 Res; 
      #if SYSTEM_SUPPORT_OS  //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS  
      OSIntEnter();     
      #endif  
      if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   
          //接收中断(接收到的数据必须是 0x0d 0x0a 结尾)   
          {   
          Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据      
          if((USART_RX_STA&0x8000)==0)//接收未完成    
              {    
              if(USART_RX_STA&0x4000)//接收到了 0x0d 
                  {     
                  if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始     
                  else USART_RX_STA|=0x8000; //接收完成了      
                  }    
              else //还没收到 0X0D     
                  {      
                  if(Res==0x0d)USART_RX_STA|=0x4000;     
                  else      
                      {      
                      USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;  
                                      //接收成功,USART_RX_BUF[]进行数据的保存 
                      USART_RX_STA++;      
                      if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; 
                      //接收数据错误,重新开始接收         
                      }        
                  }    
              }            
          }  
  #if SYSTEM_SUPPORT_OS   //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.  
  OSIntExit();               
  #endif 
  }    

EN_USART1_RX USART_REC_LEN都是在 usart.h 文件里面定义的,当需要使用串口接收的时候,我们只要在usart.h里面设置 EN_USART1_RX 为 1 就可以了。不使用的时候,设置,EN_USART1_RX 为 0 即可,这样可以省出部分 sram 和 flash,我们默认是设置 EN_USART1_RX 为 1,也就是开启串口接收的。

SYSTEM_SUPPORT_OS,则是用来判断是否使用 OS,如果使用了 OS,则调用 OSIntEnter OSIntExit 函数,如果没有使用 ucos,则不调用这两个函数(这两个函数用于实现中断嵌套处理,这里我们先不理会)。

串口使用总结

串口初始化

main()中调用以下函数进行串口初始化,默认串口1

  uart_init(115200);              //波特率 115200

若使用其他串口,需要对uart.c中的uart_init()进行修改

当数据以回车结尾会被视为接收成功,保存在数组USART_RX_BUF[]

使用中会用到的寄存器、变量

  1. USART_RX_STA

    此寄存器定义如下表所示

    bit13~0用于计数,故进行下面的操作可以得到此次接收到的数据长度,保存给变量len

      len = USART_RX_STA&0x3fff   

    bit15用于判断接收是否完成,值为1才代表接收完成,故进行下面的操作判断是否数据接收完成

      if(USART_RX_STA&0x8000)
      {
          ......      //对接收到的数据的操作都在这个if里进行
      }

     

  2. USART_RX_BUF[ ]

    接收到的数据保存在此数组中,通过取其值得到数据

    例如数据的第三个字节即为USART_RX_BUF[2]

常用的函数

  1. USART_SendData()

    向串口发送数据,仅发送一个字节。思考下面的代码即可理解

      for(t=0;t<len;t++)
          {
              USART_SendData(USART1, USART_RX_BUF[t]);                //向串口1发送数据
              while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);  //等待发送结束
          }

    这段代码的含义是:将接收到的数据,重新发送给串口1

  2. printf()

    和stdio.h提供的printf()类似,直接发送信息给串口1

  3. USART_GetFlagStatus(USARTx,USART_FLAG)

    此函数用于读取串口状态信息

    其中第一个参数填对应的串口名称,第二个参数填想要获取的状态

    例如判断数据是否发送完成,调用方法如下

      USART_GetFlagStatus(USART1,USART_FLAG_TC);

    常用while()来等待发送完成,具体见上面那段USART_SendData()的代码

 

正点原子的串口使用源码示例——main函数

   int main(void)
   {      
      u16 t;  
      u16 len;    
      u16 times=0;
      delay_init();           //延时函数初始化  
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组 2:2
      uart_init(9600);        //串口初始化 波特率:9600
      LED_Init();             //LED端口初始化
      KEY_Init();             //按键的硬件接口初始化
      BEEP_Init();            //蜂鸣器的硬件接口初始化
      while(1)
      {
          if(USART_RX_STA&0x8000)
          {                      
              len=USART_RX_STA&0x3fff;    //得到此次接收到的数据长度
              printf("\r\n您发送的消息为:\r\n\r\n");
              for(t=0;t<len;t++)
              {
                  USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
                  while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
              }
              if(USART_RX_BUF!=0)
              {
                  BEEP=!BEEP;
                  LED1=!LED1;
              }
              printf("\r\n\r\n");//插入换行
              USART_RX_STA=0;
          }else
          {
              times++;
              if(times%5000==0)
              {
                  printf("\r\n战舰STM32开发板 串口实验\r\n");
                  printf("正点原子@ALIENTEK\r\n\r\n");
              }
              if(times%200==0)printf("请输入数据,以回车键结束\n");  
              if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
              delay_ms(10);   
          }
      }    
   }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32自学笔记(五)串口通信 的相关文章

  • STM32在Debug时程序运行时间不对,Debug时定时器中断每次进入断点时间不对,定时器一开启就进入中断的解决办法

    一 Debug时程序时间不对解决办法 1 点击魔术棒 2 点击Debug 点击Settings 3 点击Trace 在Core Clock里修改为你的系统时钟 二 Debug时定时器中断每次进入断点时间不对 在Debug时 程序停下来 定时
  • GCC - 如何停止链接 malloc?

    我正在努力将我的代码缩减到最小的骨架大小 我使用的是只有 32k 闪存的 STM32F0 需要很大一部分闪存用于数据存储 我的代码已经有大约 20k 闪存大小 其中一些是由于使用了 STM32 HAL 函数 我可以在以后需要时对其进行解释和
  • 在 MCU 内部 FLASH 中从一个固件跳转到另一个固件

    我目前正在开发针对 STM32F030C8 的引导加载程序固件应用程序 我在分散文件中指定引导加载程序应用程序将占用主内存位置 0x08000000 到 0x08002FFF 扇区 0 到扇区 2 我还编写了一个主固件应用程序 存储在0x0
  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • 135-基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真+源程序

    资料编号 135 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 电机 超声波传感器 制作一个基于stm32单片机超声波非接触式感应水龙头控制系统Proteus仿真 2 通过DHT11传感器检测当前
  • rt-thread studio中新建5.0不能用

    文章目录 一 版本对比 二 文件和文件夹打斜杠 在使用RT Thread studio创建新工程5 0版本的时候 结果发现新建完成之后程序不能正常运行 但是创建4 10版本的时候却能运行 那肯定是新版本出现了BUG 一 版本对比 首先对比了
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • 匹配 STM32F0 和 zlib 中的 CRC32

    我正在研究运行 Linux 的计算机和 STM32F0 之间的通信链路 我想对我的数据包使用某种错误检测 并且由于 STM32F0 有 CRC32 硬件 并且我在 Linux 上有带有 CRC32 的 zlib 所以我认为在我的项目中使用
  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 在 Atollic TrueStudio、STM32CubeMX 中导入 C 库

    我目前正在开发 STM32F767ZI Nucleo 板和一个小安全芯片 microchip atecc508a 通过 i2c 连接进行连接 该芯片有一个可用的库加密验证库 https github com MicrochipTech cr
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • 擦除后无法写入闪存

    所以我不能在擦除后直接写入内部闪存 如果写操作之前没有擦除操作 那么我可以 有什么想法吗 编程函数返回 成功写入 值 但查看内存时 没有写入任何数据 这是代码 uint32 t pageAddress 0x08008000 uint16 t
  • STM32的HAL中实现单按、长按和双按功能

    我正在尝试实现单击 双击和长按功能来执行不同的功能 到目前为止 我已经理解了单击和长按的逻辑 但我不知道如何检测双击 至于代码 我使用计数器实现了单击和长按 但代码仅停留在第一个 if 条件上 bool single press false
  • Freertos低功耗管理

    空闲任务中的低功耗Tickless处理 在整个系统运行得过程中 其中大部分时间都是在执行空闲任务的 空闲任务之所以执行 因为在系统中的其他任务处于阻塞或者被挂起时才会执行 因此可以将空闲任务的执行时间转换成低功耗模式 在其他任务解除阻塞而准
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C

随机推荐

  • 1天精通Apipost--全网最全gRPC调试和智能Mock讲解!

    gRPC 接口调试 grpc 作为一个老程序员 xff0c 最近公司技术架构用到了gPRC xff0c 但国内很少有支持这个的工具 xff0c 大部分都只是支持http 由于我同时也是Apipost骨灰级用户 xff0c 于是就在他们官网的
  • CAN总线波特率的设定——以STM32为例

    波特率的设定 首先是几个名词的含义 xff0c CAN里面1个位的构成如下 注意采样点的位置在PBS1和PBS2的中间 根据这个位时序就可以计算波特率了 最小时间单位 xff08 Tq xff0c Time Quantum xff09 同步
  • 2021电赛备赛心路历程(含代码例程)

    作为一个电子学院学生 xff0c 大二暑假才开始自学单片机知识 xff08 还是因为报名了电赛而不得不去学 xff09 xff0c 深感愧疚 从今年7月至8 4的将近四周时间内哩哩啦啦学了一些基础模块 xff08 其中光是练习点灯和其他基础
  • 20201114-三轴云台storm32 BGC HAKRC调试+

    storm32 BGC HAKRC 2轴云台支持俯仰 xff08 抬头低头 xff09 以及横滚 xff1b 三轴多了一个航向 支持锁头模式 xff0c 拍摄更方便 可以控制俯仰通过接收机或者其他单独PWM通道 可以设置跟随模式或者锁定模式
  • KEIL5中头文件路劲包含问题

    方式1 xff1a 1 Keil中添加头文件相对路劲的方法 在c c 43 43 配置中添加路劲 xff0c 最终是将添加的绝对路径转化为相对路径 xff1b 注意 xff1a 相对路径的当前位置指 uvproj文件所在位置 在C C 43
  • php curl函数应用方法之模拟浏览器

    curl 是使用URL语法的传送文件工具 xff0c 支持FTP FTPS HTTP HTPPS SCP SFTP TFTP TELNET DICT FILE和LDAP curl 支持SSL证书 HTTP POST HTTP PUT FTP
  • WireShark基本抓包数据分析

    WireShark抓包数据分析 xff1a 1 TCP报文格式 源端口 目的端口 xff1a 16位长 标识出远端和本地的端口号 顺序号 xff1a 32位长 表明了发送的数据报的顺序 确认号 xff1a 32位长 希望收到的下一个数据报的
  • VScode下运行调试C++文件

    1 下载vscode 这个可以直接去官网下载 2 下载mingw64 下载mingw64就是下载C 43 43 的编译器g 43 43 和调试器gdb 这个也可以去官网下载 xff0c 下载安装完成后去配置环境变量 我将mingw64安装在
  • c++模板的优点和缺点

    作为C 43 43 语言的新组成部分 xff0c 模板引入了基于通用编程的概念 通用编程是一种无须考虑特定对象的描述和发展算法的方法 xff0c 因此它与具体数据结构无关 但在决定使用C 43 43 模板之前 xff0c 让我们分析一下使用
  • 基于导航网格的A星寻路(Navigation mesh)

    最近花了几个月的时间实现了导航网格寻路和导航网格自动生成 导航网格数据结构定义 由于数据之间有着层级关系 xff0c 所以采用XML进行定义 navmesh基本元素 xff1a 顶点 Verts 43 可走边 Edges 43 凸多边形 P
  • cmake 引入 动态库、静态库

    动态库 xff1a link directories PROJECT SOURCE DIR lib 添加动态连接库的路径 target link libraries project name lMNN 添加libMNN so 静态库 xff
  • 利用JSP内置对象Request和Application实现用户名密码登录注册进入首页显示

    学习目标 xff1a 实验名称 xff1a JSP内置对象目的 xff1a 掌握JSP页面的全部语法 能够编写基本的JSP网页 学习内容 xff1a 1 实验 地点 周三2单元 xff0c 10617综合一实验室 自带电脑 目的 掌握各种内
  • 【如何写CMake】一个解决方案,多个工程

    文章目录 代码参考 一个解决方案 xff0c 多个工程 xff0c 即多个exe dll lib等 代码 多加几个ADD EXECUTABLE即可 1 cmake verson xff0c 指定cmake版本 cmake minimum r
  • 指针、寄存器、位操作

    定义寄存器的绝对地址 xff0c 并转换为指针进行位操作 1 位操作示例一 define PERIPH BASE unsigned int 0x40000000 define APB2PERIPH BASE PERIPH BASE 43 0
  • 详解TCP连接的建立

    TCP首部格式 TCP报文段首部的前20个字节是固定的 xff0c 后面有4N字节是根据需要而增加的选项 xff0c 因此TCP报文段的最小长度为20字节 首部固定部分的各字段的意义如下 xff1a 1 源端口和目的端口 xff1a 加上I
  • printf打印函数的原理浅析

    printf的底层原理浅析 目录 printf的底层原理浅析前言函数变参格式解析一个简单的printf示例结语 补充 前言 最近在学习linux内核的时候用到了自定义实现的printf xff0c 学习了一下 xff0c 在此记录 xff0
  • 基于公开网站挖掘敏感信息的研究与分析- Fofa 搜索

    基于公开公开网站挖掘敏感信息的研究与分析 Fofa 搜索 一 引言 1 1项目概述 基于公开网站的敏感信息挖掘研究与分析 xff1a 针对目前网络安全整体的趋势我们从google等搜索引擎 Github等代码库 FOFA等空间搜索这三个方面
  • HTTP报文

    一 HTTP报文的结构 用于HTTP协议交互的信息 xff0c 称为HTTP报文 客户端的HTTP报文称为请求报文 xff0c 服务端的称为响应报文 HTTP报文结构如下图 xff1a 下面是请求报文的一个实例 xff1a 请求行 xff1
  • 用C++写一个UDP发送和接收程序

    发送程序Sender cpp include lt stdio h gt include lt string gt include lt iostream gt include lt winsock h gt using namespace
  • STM32自学笔记(五)串口通信

    xff08 想要深入理解就把前面的看下 xff0c 否则直接看使用总结即可 xff09 usart文件夹 usart 文件夹内包含了 usart c和usart h两个文件 这两个文件用于串口的初始化和中断接收 代码只针对了串口1 xff0