完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
实战二 · 串口通信
1. 背景知识
usart文件夹包括 .c 文件和 .h 文件,针对串口1进行了初始化和中断接收,用其他串口时需要更改。主要包括两个函数: uart_init 函数,串口初始化 USART1_IRQHandler 函数,中断响应函数 下面来解剖这两个函数 1.uart_init 函数 引入32位参数 波特率(bound) void uart_init(u32 bound) 定义结构体 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; 开启时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO, ENABLE); //使能 USART1,GPIOA 时钟 //以及复用功能时钟 使用一个内置外设的时候,要首先使能相应的GPIO时钟,然后使能复用功能时钟和内置外设时钟 ———————————————— 版权声明:本文为CSDN博主「Chorgy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xwj2633673783/article/details/112549113 不知道内置外设应该开启哪个时钟使能的时候,在参考手册搜索“系统架构/系统结构”:
//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); //初始化 GPIOA.9 发送端 //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); //初始化 GPIOA.10 接收端 GPIO配置步骤:
如何查找GPIO端口应该配置为什么模式
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //对应中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能 NVIC_Init(&NVIC_InitStructure); //中断优先级配置 NVIC_IRQChannel:
//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); //初始化串口 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断 USART_Cmd(USART1, ENABLE); //使能串口 串口配置的一般步骤几个配置需要的库函数: 1. 串口时钟使能 查询系统架构图可知,USART1挂在APB2下,需要开启时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1); 2. 串口复位 复位用于设备异常时重新配置,系统刚开始工作时也需要复位。 USART_DeInit(USART1); //复位串口 1 3. 串口参数初始化 需要初始化的参数是:波特率、字长、停止位、奇偶校验位、硬件数据流控制、收发模式 通过初始化函数完成: USART_Init(USART1, &USART_InitStructure); 结构体的成员变量配置示例如下 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); //初始化串口 4. 数据发送与接收 STM32的发送接收通过寄存器USART_DR实现,这是一个双寄存器,包含了TDR和RDR,写数据时串口就自动发送,收到数据时存储在内 发数据: void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 读数据: uint16_t USART_ReceiveData(USART_TypeDef* USARTx); 5. 串口状态 通过寄存器USART_SR读取串口状态,一共有32位只取前10位,一般我们只关注第5、6位RXNE和TC: RXNE(读数据寄存器非空):该位为1的时候,说明有数据被接收到,并且可读。此时需要尽快读取USART_DR,然后将RXNE清零或者直接置0清除 TC(发送完成):该位被置位时,USART_DR数据已经发送完成,可以设置中断。也有两种清零方式:读USART_SR,写USART_DR;直接将TC写0 读取串口状态的库函数: USART_GetFlagStatus(USART1, USART_FLAG_RXNE); USART_GetFlagStatus(USART1, USART_FLAG_TC); 串口的状态是通过宏定义实现的: #define USART_IT_PE ((uint16_t)0x0028)#define USART_IT_TXE ((uint16_t)0x0727)#define USART_IT_TC ((uint16_t)0x0626)#define USART_IT_RXNE ((uint16_t)0x0525)#define USART_IT_IDLE ((uint16_t)0x0424)#define USART_IT_LBD ((uint16_t)0x0846)#define USART_IT_CTS ((uint16_t)0x096A)#define USART_IT_ERR ((uint16_t)0x0060)#define USART_IT_ORE ((uint16_t)0x0360)#define USART_IT_NE ((uint16_t)0x0260)#define USART_IT_FE ((uint16_t)0x0160) 6. 串口使能 通过函数USART_Cmd()实现: USART_Cmd(USART1, ENABLE); //使能串口 7. 开启串口响应中断 当我们需要开启串口中断的时候,需要使能,例如: USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断 此函数的第二个入口参数是使能串口的类型,例如此例中我们需要在接收到数据的时候产生中断,就需要开启RXNE的中断USART_IT_RXNE 如果需要在发送数据结束的时候产生中断,则: USART_ITConfig(USART1,USART_IT_TC,ENABLE);//数据发送结束产生串口中断 8. 获取中断状态 比如我们使能了某个串口发生中断,当中断发生了,可以调用函数判断是否完成中断: USART_GetITStatus(USART1, USART_IT_TC) 返回值是SET,则串口发送完成中断 2. USART1_IRQHandler USART1_IRQHandler函数是串口1的中断响应函数,串口1发生中断时会跳转到其中去执行
这里有一个接收协议,利用数组USART_RX_BUF[],接收状态“寄存器”USART_RX_STA (实为一个全局变量,但是起到类似寄存器的作用),实现对串口数据的接收管理。
当接收到数据时,把数据保存在USART_RX_BUF[]中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数。 当接收到回车( 回车由0X0D和0X0A组成 ) 的第一个字节0X0D (0x0D,asc码是13,指的是回车r,把光标置于本行行首) 时,停止计数; 等待0X0A (0x0A,asc码是10,指的是换行 n,把光标置于下一行的同一列) ,标记USART_RX_STA的第15位接收完成标志,完成一次接收,等待第15位被清除后完成一次接收。 如果0X0D回车来迟,而数据超过USART_REC_LEN时,会丢弃前面的数据重新接收 配置示例 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_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; //接收数据错误,重新开始接收 } } } } #if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS OSIntExit(); #endif } 3. 硬件威廉希尔官方网站 查看原理图: USART1的RXD和TXD位于PA10和PA9,再次查找得到电气连接方式: 这里发现串口1的TXD和RXD需要用跳线帽跟PA9、PA10连接在一起 4. 主函数的一些说明 在usart.h文件中可以引入"stdio.h"头文件,并且加入一段代码,即可提供printf()函数支持,直接利用printf函数向串口发送我们需要的内容。原理及操作见下文: STM32使用printf打印串口 我们来看一下主函数设计的几个示例及要点: 1. 接收数据部分 if(USART_RX_STA & 0x8000) { len = USART_RX_STA&0x3fff;//得到此次接收到的数据长度 printf("rn 您发送的消息为:rn"); for(t=0;t while((USART1->SR & 0X40) == 0);}//等待发送结束 printf("rnrn");//插入换行 USART_RX_STA = 0; } USART_RX_STA的bit15表示接收完成标志,bit14表示接收到0X0D 2. 发送数据部分 else{ times ++; if(times % 5000 == 0){ printf("rn123456789rn"); printf("asdfghjklrnrnrn");} if(times % 200 == 0)printf("hello worldrn"); if(times % 30 == 0)LED0 =! LED0; //LED闪烁指示系统还在运行 delay_ms(10); } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1889 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1668 浏览 1 评论
1152 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
763 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1720 浏览 2 评论
1966浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
797浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
618浏览 3评论
631浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
596浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-16 02:14 , Processed in 0.680734 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号