1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
串口是一个单片机常用的外设模块,对于单片机的外部通讯,程序调试都有着十分重要的作用。所以作为嵌入式学习中一个必须掌握的外设模块,这里向大家分享的我学习小结。
1.通讯理论知识简要介绍 处理器与外部通讯主要可分别为以下两种方式: 1.并行通信:数据多位同时传输,通讯速度快,但占用IO口资源多 2.串行通信:数据单位顺序传输,通讯速度较慢,其占用IO口资源较少。 串行通信按数据传递方向又可分为一下几种类型: 1.单工:传输数据只能单向传递 2.半双工:传输数据可以进行双向传输,但在传输数据的一瞬间,数据为单向传输,实际上是一种可变方向的单工通信 3.全双工:传输数据进行双向传输过程,此类通信方式要求通信设备都具有独立的接收和发送数据能力。 串行通信按通信方式又可分为1.同步通信,2.异步通信 1.同步通信:从硬件结构上讲,其通讯接口有:1.SDA,2.SCL两个接口: SCL:时钟线,提供数据接受时序,保证数据正常传递;2.SDA:数据线,发送和接受用户所需求的数据。 2.异步通信:与同步通信上对比,没有时钟线:SCL,使用波特率等协议来确保数据传输速率。通讯接口为:RXD、TXD分别负责数据的接收和发送。 以下是一些常用的通讯协议(图片来自正点原子): 2.基于库函数的串口初始化步骤: 对于串口的初始化步骤可以分为以下几步: 1.GPIO以及串口时钟的使能 2.GPIO端口复用映射设置,如果想要使用中断的化,则需要进行NVIC中断优先级分组设置 3.GPIO端口模式初始化 4.UART模式初始化设置 5.串口使能。 如果不使用串口中断的话,使用上面配置已经就够了。若使用串口中断则需要加上中断配置。 6.中断使能以及NVIC中断初始化配置 示例(初始化USART1): void uart_init(u32 bound){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能串口时钟 USART_DeInit(USART1);//复位串口1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//设置PA9与PA10复用功能串口1 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断管理优先级分组为2,2位抢占优先级,2位响应优先级 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10; //引脚设置位Pin9与pin10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //模式设置为复用功能 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //推挽输出模式 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉模式 GPIO_InitStructure.GPIO_Speed=GPIO_Fast_Speed; //IO速率50Mhz GPIO_Init(GPIOA,&GPIO_InitStructure); USART_InitStructure.USART_BaudRate=bound; //波特率设置为bound USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无硬件流控制方式 USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//设置接收端和发送端 USART_InitStructure.USART_Parity=USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_StopBits=USART_StopBits_1;//1个停止位 USART_InitStructure.USART_WordLength=USART_WordLength_8b;//八个数据有效位 USART_Init(USART1,&USART_InitStructure);//初始化串口1 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//串口接收中断使能 NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//中断通道为USART1 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//中断通道使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//响应优先级为2 NVIC_Init(&NVIC_InitStructure);//中断初始化 USART_Cmd(USART1,ENABLE);//串口使能 } 值得特别注意的是串口和GPIO的时钟配置,此配置一般放在定义结构体后,并且串口1时钟配置函数为: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); 而GPIO时钟配置函数为: RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); 两者函数名称除了数字有区别之外,还有一个是RCC_APB开头,一个是RCC_AHB开头,千万不要写错,作者就是在这里误写成了都是RCC_AHB开头导致程序错误,花了较多时间寻找BUG。 3.串口中断函数设置 在串口一中的中断函数,我仿照正点原子进行编写,功能是一次接收多个数据,在收到回车(rn)之后,发送接收的数据到上位机。大致思路是首先定义一个u8 USART_RX_BUF[USART_REC_LEN]用来接收并储存发送给单片机串口的数据,然后定义一个u16 USART_RX_STA作为接受标志位,该变量的0-13位用于记录串口接收数据个数,14-15位为则用来判断接收是否完成,判断过程如下:首先判断USART_RX_STA第15位是否为1,如果不为1则表示接收为完成。然后继续判断第14为是否为1,若为1,则代表上一个数据为“r"(接收到了0x0d),然后再判断这一次数据是否为”n"(0x0a),如果不是则代表数据接收出现错误,将USART_RX_STA清零,重新接收。 如果判断第14为不是1,这判断此时数据是否为“r"(0x0d),如果是,则14位置1。若不是,代表数据未接收完成,将数据传入USART_RX_BUF[]数组中。 示例如下: void USART1_IRQHandler(void) //串口1中断服务程序 { u8 res=0; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){//是否发生接收中断 res=USART_ReceiveData(USART1); //读取串口数据 if((USART_RX_STA&0x8000)==0){ if((USART_RX_STA&0x4000)){ if(res!=0x0a){ USART_RX_STA=0; } else{ USART_RX_STA|=0x8000; } } else{ if(res==0x0d){ USART_RX_STA|=0x4000; } else{ USART_RX_BUF[(USART_RX_STA&0x3fff)]=res; USART_RX_STA++; if((USART_RX_STA&0x3fff)>(USART_REC_LEN-1)){ USART_RX_STA=0; } } } } } } 4.串口输出函数 输出函数主要功能为输出已经接收完成的中断,而数据还没有接收完成时,打印提示信息。 示例如下: void uart_watching(void){ int i=0; static int times=0; if((USART_RX_STA&0x8000)!=0){//接受数据完成,准备发送数据 printf("rn您发送的数据为:rn"); for(;i<(USART_RX_STA&0x3fff);i++){ USART_SendData(USART1,USART_RX_BUF); while((USART1->SR&0x40)==0); } USART_RX_STA=0; } else{ if(times%2000==0){ printf("rn只爱做控制rn"); } if(times%200==0){ printf("rn请输入数据rn"); } if(times>100000){ times=0; } times++; delay_ms(20); } } 5.学习疑点 本作者能力有限,在调试串口程序中还存在了一个疑问,在此与大家分享,希望知道答案的大牛可以在评论区写出您的答案,感激不尽! 问题:大家注意这样一段代码: printf("rn您发送的数据为:rn"); for(;i<(USART_RX_STA&0x3fff);i++){ USART_SendData(USART1,USART_RX_BUF); while((USART1->SR&0x40)==0); } printf("rn"); USART_RX_STA=0; 此段代码主要功能是在用printf函数打印“您发送的数据为:",之后向串口打印你所接受的数据。 在printf("rn您发送的数据为:rn");中句末有一个回车换行符,按照作者的理解,打印所接收的数据应该另起一行在新行打印,理想效果应该如下图所示: 作者设想的应该是上述打印效果,为数据另起一行打印“喜羊羊”。 但实际打印效果却是下图: 在”您发送的数据为:"后并没有另起一行而直接在字符后面打印数据。 尝试一:将printf("rn您发送的数据为:rn");替换成 printf("rn您发送的数据为:rnrn");,多了一个回车换行符,打印效果是作者设想的效果。 尝试二:将printf("rn您发送的数据为:rn");替换成 printf("rn您发送的数据为:");,打印效果将”:“直接省略了,效果如下图所示 尝试三:将printf(”rn您发送的数据为:rn");替换成 printf("rn您发送的数据为");,打印过程中出现乱码。 打印中文 打印数字 以上就是作者的疑问,希望各路大神热心帮助 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1767 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1069 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1935浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
728浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
567浏览 3评论
592浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
551浏览 3评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 01:07 , Processed in 0.828985 second(s), Total 79, Slave 61 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号