本帖最后由 229382777@qq.com 于 2017-2-28 10:58 编辑
买了原子的mini开发板快一年了,一直都是断断续续的学,学习进度经常被打断,导致现在连前面的知识也忘的差不多了,自身学习的条件可能没有大学生好,即将面临毕业实习,希望在最后这两个月能把mini教程全部过完并掌握,争取出去后能适应的了这方面的工作。在此借原子哥的宝地一用,也方便自己日后的复习,学习过程中可能会出现挺多错误的地方,也希望大家能帮忙指出其中错误的地方。为了保证自己的身体健康,不忙的情况下一般都会晚上9点前进行更新,每天会坚持去操场跑步。希望各位也注重身体健康,身体是革命的本钱O(∩_∩)O!
目录
所在页数 所在楼层楼层主题 1
1
1
1
1
1
1
1
2
2
2
2
2
2
2
2
3
3
3
3
3
3
3
3
4
4
4
4
4
4
4
4
4
4
4
42#
20#
25#
32#
38#
41#
44#
46#
54#
59#
60#
63#
71#
78#
85#
86#
100#
106#
110#
117#
122#
134#
144#
148#
152#
154#
155#
158#
163#
164#
167#
171#
173#
176#
185#
189#之后硬件篇
SYSTEM文件部分(一)
SYSTEM文件部分(二)
LED灯
按键
串口
外部中断
独立、窗口看门狗
定时器中断
PWM互补输出及死区时间
输入捕获
OLED
LCD
LCD(二)
RTC
待机唤醒
ADC
内部温度传感器
DAC
DMA
IIC
SPI
触摸屏
FLASH模拟EEPROM
内存管理
SD卡
FATFS
汉字显示实验
图片显示
IAP
触控USB鼠标实验
M3内核基础知识
UCOS任务调度
UCOS信号量和邮箱
消息队列、信号量、软件定时器
知识点分享
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
实战:串口
USART介绍
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。
任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输入。通过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
偶校验:校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为偶数。
例如:数据=00110101,有4个’1’,如果选择偶校验(在USART_CR1中的PS=0),校验位将是’0’。
奇校验:此校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为奇数。
例如:数据=00110101,有4个’1’,如果选择奇校验(在USART_CR1中的PS=1),校验位将是’1’。
传输模式:如果USART_CR1的PCE位被置位,写进数据寄存器的数据的MSB位被校验位替换后发送出去(如果选择偶校验偶数个’1’,如果选择奇校验奇数个’1’)。如果奇偶校验失败,USART_SR寄存器中的PE标志被置’1’,并且如果USART_CR1寄存器的PEIE在被预先设置的话,中断产生。
串口各种模式的设置
同步模式:通过在USART_CR2寄存器上写CLKEN位选择同步模式。
LIN(局域互联网)模式:是通过设置USART_CR2寄存器的LINEN位选择。
单线半双工模式:通过设置USART_CR3寄存器的HDSEL位选择。
智能卡模式:设置USART_CR3寄存器的SCEN位选择智能卡模式。
IrDA模式:通过设置USART_CR3寄存器的IREN位选择IrDA模式。
串口DMA发送接收:USART可以利用DMA连续通信。 Rx缓冲器和Tx缓冲器的DMA请求是分别产生的。使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。可以通过设置USART_CR3寄存器的DMAR位激活使用DMA进行接收
串口设置
1,串口时钟使能:APB1ENR或APB2ENR
2,串口复位:APB1RSTR或APB2RSTR
3,串口波特率设置:USART_BRR(通过计算,上面笔记有)
4,串口控制:USART_CR1~3,中文参考手册542~546页,内容比较多
5,数据发送与接收:USART_DR
6,串口状态:USART_SR
USART_SR 状态寄存器
比较重要的两个位
RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并
且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将
该位清零,也可以向该位写 0,直接清除。
TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如
果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写
USART_DR。 2)直接向该位写 0。
USART_DR寄存器
DR[8: 0]为串口数据,包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能。 TDR 寄存器提供了内部总
线和输出移位寄存器之间的并行接口。 RDR 寄存器提供了输入移位寄存器和内部总线之间的并
行接口。如下图
半主机模式:
这种机制很有用,因为开发时使用的硬件通常没有最终系统的所有输入和输出设备。 半主机可让主机来提供这些设备。半主机是通过一组定义好的软件指令(如 SVC)来实现的,这些指令通过程序控制生成异常。 应用程序调用相应的半主机调用,然后调试代理处理该异常。 调试代理提供与主机之间的必需通信。半主机是用于 ARM 目标的一种机制,可将来自应用程序代码的输入/输出请求传送至运行调试器的主机。例如,使用此机制可以启用 C 库中的函数,如 printf() 和 scanf(),来使用主机的屏幕和键盘,而不是在目标系统上配备屏幕和键盘。
简单的来说,半主机模式就是通过仿真器实现开发板在电脑上的输入和输出。机制的运行需要仿真器,否则无法运行, 开发式一般单片机需要独立运行,开发者应去掉仿真器,把printf函数通过单片机的外设来实现,例如通过开发板的串口,lcd或者sd卡。
以下是串口初始化代码
[mw_shl_code=c,true]void uart_init(u32 pclk2,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV,前面的笔记已经解释,这里就不重复了 mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分 mantissa<<=4; mantissa+=fraction; RCC->APB2ENR|=1<<2; //使能PORTA口时钟 RCC->APB2ENR|=1<<14; //使能串口时钟 GPIOA->CRH&=0XFFFFF00F;//IO状态设置 GPIOA->CRH|=0X000008B0;//IO状态设置 RCC->APB2RSTR|=1<<14; //复位串口1 RCC->APB2RSTR&=~(1<<14);//停止复位 //波特率设置 USART1->BRR=mantissa; // 波特率设置 USART1->CR1|=0X200C; //1位停止,无校验位(原子哥这里应该备注错误了,停止位是通过CR2的12和13位来设置的,CR1设置不了,这里应该备注为USART使能,发送接收使能) #if EN_USART1_RX //如果使能了接收 //使能接收中断 USART1->CR1|=1<<8; //PE中断使能 USART1->CR1|=1<<5; //接收缓冲区非空中断使能 MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级 #endif } [/mw_shl_code]
上面初始化过程也发现原子哥有个备注写错了,USART1->CR1|=0X200C;备注的是1位停止位,停止位是通过CR2的12和13位来设置的,CR1设置不了,这里应该备注为USART使能,发送接收使能。
[mw_shl_code=c,true]typedef struct{ unsigned REC_Num : 14; //前0~13位保存接收到的字节数 unsigned REC_0X0D : 1; //收到0x0d表示换行 unsigned REC_END : 1; //结束一次接收 }usart_rx_sta; usart_rx_sta USART_RX_STA; //接收状态标记 void USART1_IRQHandler(void) { u8 res; if(USART1->SR&(1<<5))//接收到数据 { res=USART1->DR; if(USART_RX_STA.REC_END == 0)//接收未完成 { if(USART_RX_STA.REC_0X0D == 1)//接收到了0x0d { if(res!=0x0a) memset(&USART_RX_STA, 0 ,sizeof(USART_RX_STA));//接收错误,重新开始 else USART_RX_STA.REC_END = 1; //接收完成了 }else //还没收到0X0D { if(res==0x0d)USART_RX_STA.REC_0X0D = 1; else { USART_RX_BUF[USART_RX_STA.REC_Num]=res; USART_RX_STA.REC_Num++; if(USART_RX_STA.REC_Num>(USART_REC_LEN-1)) memset(&USART_RX_STA, 0 ,sizeof(USART_RX_STA));//接收数据错误,重新开始接收 } } } } } [/mw_shl_code]
程序的运行结果都是一样的,基于考虑实际项目,串口需要有个超时机制,以下附上自己常用的超时机制的代码,如果超过50ms都还没接收到数据则强制接收结束。以下是代码
[mw_shl_code=c,true]/* * 函数名:UartRxMonitor * 描 述:UART通信接收的监控函数,用于判定一帧数据的接收完成 * 输 入:ms - 本函数调用的间隔时间,单位ms,直接开个定时器,每毫秒中断一次,形参设为1即可 * 输 出:无 */ void UartRxMonitor(u8 ms) { u8 cnt; static u8 cntbkp=0; static u8 idletmr=0; static u8 sigpost=0; cnt = usart3_get_long; //帧的长度 if (cnt == 0) { //没接收到数据 cntbkp = 0; //当前长度清零 return; } if (cnt != cntbkp) { //接收到了新数据,累加的时间清零,如果前后长度相等则开始ms的累加 idletmr = 0; //时间累计清零 sigpost = 0; //超时标志清零 cntbkp = cnt; //记下当前长度 return; } if (sigpost != 0) { //保证接收完成标志只推送一次 return; } idletmr += ms; //毫秒数累计,50ms if (idletmr >= FRAME_SPACE_TIME) { //如果超过50ms长度依旧相等,则说明超时了,FRAME_SPACE_TIME是个宏定义,等于50 sigpost = 1; //超时标志 //可以强制接收完成 //也可以丢弃接收缓冲区的数据,看自己需求 } }[/mw_shl_code]一周热门 更多>