菜鸟学STM32之串口通讯

摘要:
串口作为MCU的重要外部接口,也是软件开发的重要调试手段,其重要性不言而喻。目前,几乎所有的MCU都有串行端口,STM32也不例外。STM32F4具有丰富的串口资源和强大的功能。STM32F4开发板使用的STM32F407ZGT6最多可提供六个串行端口,包括分数波特率发生器、支持同步单线通信和半双工单线通信、支持LIN、支持调制解调器操作、智能卡协议和IrDASIENDEC规范以及DMA。

微信公众号:小樊Study
关注共同学习,问题或建议,请公众号留言!!!

串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。现在基本上所有的MCU都会带有串口,STM32自然也不例外。STM32F4的串口资源相当丰富的,功能也相当强劲。STM32F4开发板所使用STM32F407ZGT6 最多可提供 6 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA 等。
我们将实现利用串口1不停的打印信息到电脑上,同时接收从串口发过来的数据,把发送过来的数据直接送回给电脑.

硬件连接

菜鸟学STM32之串口通讯第1张
tx是发送(transport),rx是接收(receive)

 

软件设计

uart.c

  1#include "sys.h"
2#include "usart.h"    
3//////////////////////////////////////////////////////////////////////////////////      
4//如果使用ucos,则包括下面的头文件即可.
5#if SYSTEM_SUPPORT_OS
6#include "includes.h"                    //ucos 使用     
7#endif
8
9//加入以下代码,支持printf函数,而不需要选择use MicroLIB      
10#if 1
11#pragma import(__use_no_semihosting)             
12//标准库需要的支持函数                 
13struct __FILE 
14{
 
15    int handle; 
16}; 
17
18FILE __stdout;       
19//定义_sys_exit()以避免使用半主机模式    
20_sys_exit(int x) 
21
22    x = x; 
23
24//重定义fputc函数 
25int fputc(int ch, FILE *f)
26
{     
27    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
28    USART1->DR = (u8) ch;      
29    return ch;
30}
31#endif
32
33#if EN_USART1_RX   //如果使能了接收
34//串口1中断服务程序
35//注意,读取USARTx->SR能避免莫名其妙的错误       
36u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
37//接收状态
38//bit15,    接收完成标志
39//bit14,    接收到0x0d
40//bit13~0,    接收到的有效字节数目
41u16 USART_RX_STA=0;       //接收状态标记    
42
43//初始化IO 串口1 
44//bound:波特率
45void uart_init(u32 bound){
46   //GPIO端口设置
47  GPIO_InitTypeDef GPIO_InitStructure;
48    USART_InitTypeDef USART_InitStructure;
49    NVIC_InitTypeDef NVIC_InitStructure;
50
51    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
52    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
53
54    //串口1对应引脚复用映射
55    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
56    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
57
58    //USART1端口配置
59  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
60    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
61    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //速度50MHz
62    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
63    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
64    GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
65
66   //USART1 初始化设置
67    USART_InitStructure.USART_BaudRate = bound;//波特率设置
68    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
69    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
70    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
71    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
72    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
73  USART_Init(USART1, &USART_InitStructure); //初始化串口1
74
75  USART_Cmd(USART1, ENABLE);  //使能串口1 
76
77    //USART_ClearFlag(USART1, USART_FLAG_TC);
78
79#if EN_USART1_RX    
80    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
81
82    //Usart1 NVIC 配置
83  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
84    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
85    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;       //子优先级3
86    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
87    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
88
89#endif
90
91}
92
93
94void USART1_IRQHandler(void)                    //串口1中断服务程序
95
{
96    u8 Res;
97#if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
98    OSIntEnter();    
99#endif
100    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
101    {
102        Res =USART_ReceiveData(USART1);//(USART1->DR);  //读取接收到的数据
103
104        if((USART_RX_STA&0x8000)==0)//接收未完成
105        {
106            if(USART_RX_STA&0x4000)//接收到了0x0d
107            {
108                if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
109                else USART_RX_STA|=0x8000;  //接收完成了 
110            }
111            else //还没收到0X0D
112            {   
113                if(Res==0x0d)USART_RX_STA|=0x4000;
114                else
115                {
116                    USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
117                    USART_RX_STA++;
118                    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收      
119                }        
120            }
121        }            
122  } 
123#if SYSTEM_SUPPORT_OS     //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
124    OSIntExit();                                             
125#endif
126
127#endif    

首先看一下uart_init 函数
从该代码可以看出,其初始化串口的过程,。我用标号①~⑥标示了顺序:
① 串口时钟使能,GPIO 时钟使能
② 设置引脚复用器映射
③ GPIO 端口初始化设置
④ 串口参数初始化
⑤ 初始化 NVIC 并且开启中断
⑥ 使能串口
这里需要注意一点,因为使用到了串口的中断接收,必须在 usart.h 里面设置
EN_USART1_RX 为 1(默认设置就是 1 的)。该函数才会配置中断使能,以及开启串口 1 的 NVIC中断。这里我们把串口 1 中断放在组 2,优先级设置为组 2 里面的最低。
void USART1_IRQHandler(void)函数是串口 1 的中断响应函数,当串口 1 发生了相应的中断后,就会跳到该函数执行。中断相应函数的名字是不能随便定义的,一般我们都遵循MDK 定义的函数名。这些函数名字在启动文件 startup_stm32f40_41xxx.s 中可以找到
main.c

 1#include "sys.h"
2#include "delay.h"
3#include "usart.h"
4#include "led.h"
5#include "beep.h"
6#include "key.h"
7
8int main(void)
9

10
11    u8 t;
12    u8 len; 
13    u16 times=0;  
14    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
15    delay_init(168);        //延时初始化 
16    uart_init(115200);  //串口初始化波特率为115200
17    LED_Init();             //初始化与LED连接的硬件接口  
18    while(1)
19    {
20        if(USART_RX_STA&0x8000)
21        {                      
22            len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
23            printf(" 您发送的消息为: ");
24            for(t=0;t<len;t++)
25            {
26                USART_SendData(USART1, USART_RX_BUF[t]);         //向串口1发送数据
27                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
28            }
29            printf(" ");//插入换行
30            USART_RX_STA=0;
31        }else
32        {
33            times++;
34            if(times%5000==0)
35            {
36                printf(" ALIENTEK 小樊Study 串口实验 ");
37                printf("小樊Study ");
38            }
39            if(times%200==0)printf("请输入数据,以回车键结束 ");  
40            if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
41            delay_ms(10);   
42        }
43    }
44}

下载验证

我们把程序下载到探索者 STM32F4 开发板,可以看到板子上的 DS0 开始闪烁,说明程序已经在跑了。
接着我们打开 XCOM V2.0,设置串口为开发板的 USB 转串口(CH340 虚拟串口,得根据你自己的电脑选择,我的电脑是 COM3,另外,请注意:波特率是 115200),可以看到

菜鸟学STM32之串口通讯第2张
可以看出,STM32F4 的串口数据发送是没问题的了。但是,因为我们在程序上
面设置了必须输入回车,串口才认可接收到的数据,所以必须在发送数据后再发送一个回车符,这里 XCOM 提供的发送方法是通过勾选发送新行实现,只要勾选了这个选项,每次发送数据后,XCOM 都会自动多发一个回车(0X0D+0X0A)。设置好了发送新行,我们再在发送区输入你想要发送的文字,然后单击发送,可以得到如图所示结果:
菜鸟学STM32之串口通讯第3张

 

下面的是我的公众号二维码图片,欢迎关注。

图注:小樊Study图注:小樊Study

免责声明:文章转载自《菜鸟学STM32之串口通讯》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇supervisor使用TCPDF说明文档下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32学习笔记——USART串口(向原子哥和火哥学习)

一、USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。 STM32 的串口资源相当丰富的,功能也相当强劲。STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持...

重新初始化RAC的OCR盘和Votedisk盘,修复RAC系统

假设我们的RAC环境中OCR磁盘和votedisk磁盘全部被破坏,并且都没有备份,那么我们该如何恢复我们的RAC环境。最近简单的办法就是重新初始化我们的ocr盘和votedisk盘,把集群中的所有相关资源重新注册到OCR磁盘和votedisk磁盘中。 1.停掉所有节点的Clusterware Stack [root@rac3 bin]# ./crsctl...

linux 下nginx

所有的配置文件都在/etc/nginx (ect/nginx/nginx.conf) 下,并且每个虚拟主机已经安排在 了/etc/nginx/sites-available 程序文件在/usr/sbin/nginx 日志放在了/var/log/nginx中 并已经在/etc/init.d/下创建了启动脚本 nginx -------------------...

rootkit:实现隐藏进程

实现隐藏进程一般有两个方法: 1,把要隐藏的进程PID设置为0,因为系统默认是不显示PID为0的进程。 2,修改系统调用sys_getdents()。 Linux系统中用来查询文件信息的系统调用是sys_getdents,这一点可以通过strace来观察到,例如strace ls 将列出命令ls用到的系统调用,从中可以发现ls是通过getdents系统调用...

【转】RO段、RW段和ZI段 Image$$??$$Limit 含义(zz)

作者评注:内容很多,不过解释讲解详细 http://www.cnblogs.com/heart-of-eagle/archive/2011/04/28/2032240.html 转载:          IMPORT |Image$$RO$$Limit|      IMPORT |Image$$RW$$Base|      IMPORT |Image$$Z...

类的加载过程(类的生命周期)详解

3.1. 概述 在Java中数据类型分为基本数据类型和引用数据类型。基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载。 按照Java虚拟机规范,从class文件到加载到内存中的类,到类卸载出内存为止,它的整个生命周期包括如下7个阶段: 其中,验证、准备、解析3个部分统称为链接(Linking) 从程序中类的使用过程看 大厂面试题 蚂蚁金服...