关于串口吧
简单谈下吧,其实只是会用单片机的串口并不算是真正意义上的串口了,为什么呢,因为,只有学了FPGA
的串口实现才能较为深入的了解这个协议
1.发送
2.接收
3.波特率
/***********************************************************************************************/
基于寄存器的
1.发送
发送是采用查询的模式来发送的,很简单的,因为发送是由你来确定的,你可以确定
什么时候想发送就发送,所以查询就可以,不需要用的上中断,除了一些特别的情况
2.接收
接收的话,就不能采用查询了,其实也可以但是这样很浪费资源,为什么呢,因为你从板子上电一开始
就一直在查询有没有东西传过来,所以这种方法不可取,为什么呢?因为我们有更好的办法,是的,中断,
我CPU只需要做我相应的事情就好了,只要等着你传东西过来,然后我产生中断,压栈,然后保护现场
等着你处理完事情恢复现场,出栈就好了,继续做我没做完的事情,中断模式在这里用的很方便
3.关于波特率
我必须要说点什么了,之前用FPGA来做串口,差点没把我搞死,因为我没想到这么难,完全不同于之前
用MCU学的,然后什么产生波特率,然后发送模块,接收模块,最后再组合就OK了,但是单片机这里
只需要设置就行了,请注意我的措辞,用FPGA是产生波特率,并不是设置,并不是只需要配置相应的寄存器
就行了,是要根据时钟来计算产生不同的波特率,但是单片机和FPGA的差别就体现在这里,只需要配置相应
的寄存器,学会计算就OK了,简单吧。但我仍是卡在这里很长时间,为什么呢,因为我在进行这一块的时候
波特率一直配置不对,后来才发现,是我一开始时钟HSE没配置好,原来我用的一直是HSI,简直无语了
搞了这么长时间,原来时钟没配置好,打击很大有木有?
接下来谈下这个 小数波特率的生成,这里有个公式,
波特率 = FCLK / 8(2 - OVER8)* USARTDIV
好吧,这个时钟就是PCLK2 ,OVER8就是过采样模式的寄存器的值,可供选择到底是16倍过采样,还是8倍
过采样,一般都会选择最大的对吧,越大越好,是的,我也是这样认为的,可以从字面意思上看出这个过采样
就是采样的速率或者是简单点理解位采样的多少,那当然越大越好了,越大可以减少误差啊,那么数据传输的
可靠性就得到保证了,但是吧,这里需要注意一点,关于串口波特率的选择官方手册上有个表,就是说当误差
低到某种程度之后,已经不影响波特率的选择和数据的传输了,也就是说这些误差可以忽略不计了,大概我理解
是这个意思,具体可以去看那个波特率的表。
好吧,又扯远了,USARTDIV 是一个存放在 USART_BRR 寄存器中的无符号定点数,我们设置波特率就是为了主要
确定这个东西然后才可以得出我们想要的波特率,所以我们可以反其道而行之,我们先确定我们需要的波特率
然后再算出这个定点数,写入寄存器,然后把其他配置好就可以得到波特率了,当然这里还是有一些需要注意的
下面大致是设置一个波特率的过程,很容易看懂
至于那个条件编译是针对我自己的时钟设置的,所以没必要看,只需要知道,根据时钟和想要的波特率先算出
temp,是个小数,注意16,是因为我们设置的是16倍过采样,然后吧,默认OVER8为0,所以为16,很简单的
侮辱大家智商了...得出temp后首先取整,作为USART_DIV的一部分,然后是小数部分,需要*16,至于为什么
这样,我也不是很清楚,我当初看的是ATK是这样写的,后来去查了下官方手册写的例子,好像也是这样,
应该跟16倍过采样有关吧,有时候只需要知道这样设置就行了,没必要懂为什么。然后相加求和可以得出
我们所想要的USART_DIV,这就是我们需要向波特率寄存器写入的值。
至此,波特率设置完成。
/***********************************************************************************************/
static float temp;
uint16_t temp_int,temp_point;
uint16_t USART_DIV;
#if CLK_168 //168MHZ Only in this case can enable OTG(clock must be 48M)
temp = (84 * 1000000.0) / (115200 * 16);
#elif CLK_160 //160MHZ
temp = (80 * 1000000.0) / (115200 * 16);
#elif CLK_80 //80MHZ
temp = (40 * 1000000.0) / (115200 * 16);
#elif CLK_72 //72MHZ
temp = (36 * 1000000.0) / (115200 * 16);
#endif //<CLK_168>
temp_int = (uint16_t) temp; //int
temp_point = (uint16_t)((temp - temp_int) * 16); //point
temp_int <<= 4; //left move
USART_DIV = temp_int + temp_point;
return USART_DIV;.
/***********************************************************************************************/
然后就没了。根据手册寄存器设置需要设置的就行了
4.关于重定向
这个很简单的,就是和那个VC 6.0一样,把需要打印的值打印到串口,专业点就是说重定向到串口,简单易懂
直接上代码,一个函数解决问题
int
fputc(int ch, FILE *f)
{
while (!(USART1->SR & 1<<6));
USART1->DR = (uint8_t)ch;
return ch;
}
中间出了点问题,是关于FILE的,是在stdio.h文件中定义的,但是IAR对这个文件设置了只读,有个条件编译
没有使能,所以找不到这个定义的任何信息,然后只需要把只读改了就行了,然后使能条件编译再加上只读
OK 大功告成!!!
5.至于发送函数,是需要使用指针的,比如发送一个字符串或者一行文字,printf这个重定向最好尽量只是给
串口看就可以了,我不习惯用这个函数来当串口Triansmit 函数,所以这个坑还在,日后需要使用发送函数
自己还得补上,然后把,接收就好多了,定义个数组,把接收到的放到数组里就OK了,只要数组够大。
然后就这样吧。
6.补充下,关于USART的,其实串口有很多模式的,比如什么同步异步之类的,但是我们通常用的都是异步,
为什么呢?因为异步更方便不用考虑传送数据的双方需要约定在一个时间才能传输,异步就是你只管发,我不一定
同步和你接收,我什么时候有空再接收就行。蛮方便的,但是某些条件下需要用同步的,这个遇到具体情况再考虑,
平时用来看个数据什么的都是异步!!!
了解这个概念就行了
7.关于串口
最新推荐文章于 2024-03-25 11:39:38 发布