完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
一、通信的基本概念
1.同步通信和异步通信 (1)同步和异步的区别 同步:发送方和接受方按照同一个时钟节拍工作 异步:发送方和接受方按照各自的节拍工作 (2)同步通信中,通信双方按照统一节拍工作,所以配合好;一般需要发送方给接受方发送信息同时发送时钟信号,接受方根据发送方给他的时钟信号来安排自己的节奏。同步通信用在通信双方信息交换频率固定,或者经常通信时。 (3)异步通信又叫异步通知。在双方通信的频率不固定时(有时3ms收发一次,有时3天收发一次)不适合使用同步通信,而适合异步通信。异步通信时接收方不必一直在意发送方,发送方需要发送信息时会首先给接收方一个信息开始的起始信号,接收方接收到起始信号后就认为后面紧跟着的就是有效信息,才会开始注意接收信息,直到收到发送方发过来的结束标志。 2.电平信号和差分信号 (1)电平信号和差分信号是用来描述通信线路传输方式的。也就是说如何在通信线路上表达1和0。 (2)电平信号通信的传输线中有一个参考电平线(一般是GND),然后信号线上的信号值是由信号线电平和参考电平线的电压差决定的。 (3)差分信号的传输线中没有参考电平,所以都是信号线。然后1和0的表达靠信号线之间的电压差。 总结: 电平信号的传输线之间的2根通信线之间的电平差异容易受到干扰,传输容易失败; 差分信号不容易受到干扰因此传输质量比较稳定,现代通信一般都使用差分信号 看起来似乎相同根数的通信线下,电平信号要比差分信号要快;但是实际还是差分信号快,因为差分信号抗干扰能力强,因此1个发送周期更短。 3.并行接口和串行接口 (1)串行、并行主要是考虑通信线的根数,就是发送方和接受方同时可以传递的信息量的多少 (2)譬如在电平信号下,1根参考电平线+1根信号线可以传递1位二进制;如果我们有3根线(2根信号线+1根参考线)就可以同时发送2位二进制;如果想同时发送8位二进制就需要9根线。 (3)在差分信号下,2根线(彼此差分)可以同时发送1位二进制;如果需要同时发送8位二进制,需要16根线。 总结:听起来似乎并行接口比串行接口要快(串行接口一次只能发送1位二进制,而并行接口一次可以发送多位二进制)要更优秀;但是实际上串行接口才是王道,用的比较广。因为更省信号线,而且对传输线的要求更低、成本更低;而且串行时可以通过提高通信速度来提高总体通信性能,不一定非得要并行。 其实这么多年发展,最终胜出的是:异步、串行、差分,譬如USB和网络通信。 4.单工通信和双工通信 单工通信:单方向 双工通信:双方同时收发 半双工:同时只能单方向收发,但是方向可以改变,如A发B收或者B发A收(两个方向不能同时) 全双工:同时收发,如A发B收同时B发A收 二、串口通信的基本概念 1.串口通信的特点:异步、电平信号、串行 异步:串口通信的发送方和接收方之间是没有统一的时钟信号的。 电平信号:串口通信出现的时间较早,速率较低,传输的距离较近,所以干扰还不太明显,因此当时使用了电平信号传输。后期出现的传输协议都改成差分信号传输了。 串行通信:串口通信每次同时只能传输1个二进制位。 2.RS232电平和TTL电平 电平信号是用信号线电平减去参考线电平得到电压差,这个电压差决定了传输值是1还是0. 在电平信号时多少V代表1,多少V代表0不是固定的,取决于电平标准。譬如RS232电平中-3V~-15V表示1;+3~+15V表示0;TTL电平则是+5V表示1,0V表示0. 不管哪种电平都是为了在传输线上表示1和0.区别在于适用的环境和条件不同。RS232的电平定义比较大,适合干扰大、距离远的情况;TTL电平电压范围小,适合距离近且干扰小的情况。 我们台式电脑后面的串口插座就是RS232接口的,在工业上用串口时都用这个,传输距离小于15米;TTL电平一般用在电路板内部两个芯片之间。 对编程来说,RS232电平传输还是TTL电平是没有差异的。所以电平标准对硬件工程师更有意义,而软件工程师只要略懂即可。(把TTL电平和RS232电平混接是不可以的) 3.波特率 波特率(bandrate),指的是串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位。譬如每秒种可以传输9600个二进制位(传输一个二进制位需要的时间是1/9600秒,也就是104us),波特率就是9600. 串口通信的波特率不能随意设定,而应该在一些值中去选择。一般最常见的波特率是9600或者115200(低端单片机如51常用9600,高端单片机和嵌入式SoC一般用115200). 为什么波特率不可以随便指定?主要是因为: 第一,通信双方必须事先设定相同的波特率这样才能成功通信,如果发送方和接收方按照不同的波特率通信则根本收不到,因此波特率最好是大家熟知的而不是随意指定的。 第二,常用的波特率经过长久发展,就形成了共识,大家常用就是9600或者115200. 4.起始位、数据位、奇偶校验位、停止位 (1)串口通信时,收发是一个周期一个周期进行的,没周期传输n个二进制位。这一个周期就叫做一个通信单元,一个通信单元是由:起始位+数据位+奇偶校验位+停止位组成的。 (2)起始位表示发送方要开始发送一个通信单元;数据位是一个通信单元中发送的有效信息位;奇偶校验位是用来校验数据位,以防止数据位出错的;停止位是发送方用来表示本通信单元结束标志的。 (3)起始位的定义是串口通信标准事先指定的,是由通信线上的电平变化来反映的。 (4)数据位是本次通信真正要发送的有效数据,串口通信一次发送多少位有效数据是可以设定的(一般可选的有6、7、8、9,99%情况下我们都是选择8位数据位。因为我们一般通过串口发送的文字信息都是ASCII码编码的,而ASCII码中一个字符刚好编码为8位。) (5)奇偶校验位是用来给数据位进行奇偶校验(把待校验的有效数据逐个位的加起来,总和为奇数奇偶校验位就为1,总和为偶数奇偶校验位就为0)的,可以在一定程度上防止位反转。 (6)停止位的定义是串口通信标准事先指定的,是由通信线上的电平变化来反映的。常见的有1位停止位,1.5位停止位,2位停止位等。99%情况下都是用1位停止位。 4.说说串口通信 三根通信线:Rx,Tx,GND (1)任何通信都要有传输载体,或者是有线的或者是无限的。 (2)串口通信是有线通信,是通过串口线来通信的。 (3)串口通信最少需要2根(GND和信号线),可以实现单工通信。也可以使用2根通信线(Tx,Rx,GND)来实现全双工。 (4)一般开发板都会引处SoC上的串口引脚直接输出的TTL电平的串口,插座用插座用插针式插座,每个串口引出的都有3个线(Tx、Rx、GND),可以用这些插座直接连接外部的TTL电平的串口设备。 5.信息在信道上传输方式 串口通信的发送方每隔一段时间(时间固定为1/波特率,单位是秒)将有效信息(1或者0)放到通信线上去,逐个二进制位的进行发送。 接收方通过定时,起始时间由读到起始位标志开始,间隔时间由波特率决定,读取通信线上的电平高低来区分发送的是1还是0,。依次读取数据位、奇偶校验位、停止位,停止位就表示这一个通信单元(帧)结束,然后中间是不定长短的非通信时间(发送方有可能紧接着就发送第二帧,也可能半天都不发第二帧,这就叫异步通信),接着发送第二帧····· 串口发送的一般都是字符,一般都是ASCII码编码后的字符,所以一般设置数据位都是8,方便刚好一帧发送1个字符。 6.FIF0模式及其作用 (1)FIFO就是first in first out,先进先出。FIFO其实是一种数据结构,这里这个大的缓冲区叫FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。 (2)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这样在单片机中没什么问题,但是到复杂SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文。 (3)解决方案就是想办法扩展串口控制器的发送/接收缓冲区,譬如将发送/接收缓冲器设置为64字节,CPU一次过来直接给发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了个变相的扩展,就是FIFO。 7.DMA模式及其作用 DMA direct memory access,直接内存访问。DMA本来是DSP中的一种技术,DMA技术的核心就是在交换数据时不需要CPU参与,模块可以自己完成。 DMA模式要解决的问题和上面FIFO模式是同一个问题,就是串口发送/接收要频繁的折腾CPU造成CPU反复切换上下文导致系统效率低下。 传统的串口工作方式(无FIFO无DMA)效率是最低的,适合低端单片机;高端单片机上CPU事物繁忙所以都需要串口能够自己完成大量数据发送/接收。这时候就需要FIFO或者DMA模式。FIFO模式是一种轻量级的解决方案,DMA模式适合大量数据迸发式的发送/接收时。 8.IrDA模式及其用法 (1)IrDA其实就是红外,红外就是红外线通信(电视机、空调遥控器就是红外通信的)。 (2)红外通信的原理是发送方固定间隔时间向接收方发送红外信号(表示1或0)或者不发送红外信号(表示0或者1),接收方每隔固定时间去判断有无红外线信号来接收1和0. (3)分析可知,红外通信和串口通信非常像,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。 (4)210的某个串口支持IrDA模式,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持的),然后接收方接收这些红外数据即可解码得到我们的发送信息。 三、配置串口寄存器 1.配置前的准备 第一步:确认UART的时钟。可以看之前的时钟篇(参考文档) 时钟为66MHz,挂载在APB总线上(因为APB总线的推荐设置时钟频率为66MHz),知道时钟来计算波特率的值。 第二步:寻找串口的GPIO口。查看原理图得: 可得:初始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知Rx和Rx分别对应GPA0_1和GPA0_0) 查数据手册: 通过设置GPA0CON寄存器的[7:0]为0x22,即可配置UART0的输入输出端口。 第三步:初始化的设置这几个关键寄存器 ULCON0 :0x3 // 0校验位、8数据位、1停止位 UCON0:0x5 // 发送和接收都是polling mode UMCON0 :0x0 // 禁止modem、afc UFCON0:0x0 // 禁止FIFO模式 UBRDIV0:和波特率有关,要根据公式去算的 UDIVSLOT0:和波特率有关,要根据公式去算的 需要设置数据的接口模式、数据位、校验方式、停止位,找到对应的寄存器ULCON0(Address = 0xE290_0000)。 通过设置ULCON0寄存器的[6:0]为0x3,即将串口配置为:普通模式、无校验、1个停止位、8个数据位。 接着需要设置传输方式,找到对应的寄存器UCON0(Address = 0xE290_0004)。 通过设置UCON0寄存器的[5:0]为0x5,即将串口配置为:PCLK为时钟源,中断全关,polling mode(轮询模式)。 设置控制流控,找到对应的寄存器UMCON0(Address = 0xE290_000C),将其设置为0x0全部禁止。 设置是否使用FIFO,找到对应的寄存器UFCON0(Address = 0xE290_0008),将其设置为0x0全部禁止。 最后是设置波特率,找到对应寄存器UBRDIV0(Address = 0xE290_0028)和UDIVSLOT0(Address = E290_002C)。 已知PCLK=66.7Mhz,根据公式可得DIV_VAL = (66700000/(115200x16)-1) = 35.18,即为35;UDIVSLOT中的1的个数 = 160.18= 2.88 = 3,查找3对应的码为0x0888,波特率配置完成。 #define GPA0CON 0xE0200000 #define UCON0 0xE2900004 #define ULCON0 0xE2900000 #define UMCON0 0xE290000C #define UFCON0 0xE2900008 #define UBRDIV0 0xE2900028 #define UDIVSLOT0 0xE290002C #define UTRSTAT0 0xE2900010 #define UTXH0 0xE2900020 #define URXH0 0xE2900024 #define rGPA0CON (*(volatile unsigned int *)GPA0CON) #define rUCON0 (*(volatile unsigned int *)UCON0) #define rULCON0 (*(volatile unsigned int *)ULCON0) #define rUMCON0 (*(volatile unsigned int *)UMCON0) #define rUFCON0 (*(volatile unsigned int *)UFCON0) #define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0) #define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0) #define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0) #define rUTXH0 (*(volatile unsigned int *)UTXH0) #define rURXH0 (*(volatile unsigned int *)URXH0) // 串口初始化程序 void uart_init(void) { // 初始化Tx Rx对应的GPIO引脚 rGPA0CON &= ~(0xff<<0); // 把寄存器的bit0~7全部清零 rGPA0CON |= 0x00000022; // 0b0010, Rx Tx // 几个关键寄存器的设置 rULCON0 = 0x3; rUCON0 = 0x5; rUMCON0 = 0; rUFCON0 = 0; // 波特率设置 DIV_VAL = (PCLK / (bps x 16))-1 // PCLK_PSYS用66MHz算 余数0.8 //rUBRDIV0 = 34; //rUDIVSLOT0 = 0xdfdd; // PCLK_PSYS用66.7MHz算 余数0.18 // DIV_VAL = (66700000/(115200*16)-1) = 35.18 rUBRDIV0 = 35; // (rUDIVSLOT中的1的个数)/16=上一步计算的余数=0.18 // (rUDIVSLOT中的1的个数 = 16*0.18= 2.88 = 3 rUDIVSLOT0 = 0x0888; // 3个1,查官方推荐表得到这个数字 } // 串口发送程序,发送一个字节 void uart_putc(char c) { // 串口发送一个字符,其实就是把一个字节丢到发送缓冲区中去 // 因为串口控制器发送1个字节的速度远远低于CPU的速度,所以CPU发送1个字节前必须 // 确认串口控制器当前缓冲区是空的(意思就是串口已经发完了上一个字节) // 如果缓冲区非空则位为0,此时应该循环,直到位为1 while (!(rUTRSTAT0 & (1<<1))); rUTXH0 = c; } // 串口接收程序,轮询方式,接收一个字节 char uart_getc(void) { while (!(rUTRSTAT0 & (1<<0))); return (rURXH0 & 0x0f);//只有低8位有用 } 2.配置发送 uart_putc()函数用来发送数据,通过调用来发送一字节的内容。其实就是向发送端缓冲区写内容,发送端缓冲区寄存器为UTXH0(Address = 0xE290_0020),一次写一个字节,因为是char型 但是要注意,由于CPU的速度远高于串口,因此CPU给缓冲区发完数据以后就去干别的工作了,所以需要一个标志来表示缓冲区已发送完毕。这就需要用到缓冲区状态寄存器UTRSTAT0(Address = 0xE290_0010),当发送端缓冲区为1时为空,因此可以设置一个条件,当UTRSTAT0=0x10时,则请求CPU发送下一字节。 |
|
|
|
只有小组成员才能发言,加入小组>>
2983 浏览 9 评论
2697 浏览 16 评论
3221 浏览 1 评论
8457 浏览 16 评论
3787 浏览 18 评论
6968浏览 6评论
求助,请问MS51FB9AE带隙电压能作为侦测的基准电压吗?
7462浏览 3评论
6962浏览 3评论
支持UART-to-BLE透传的新唐NuTool – BLE ATCMD开发工具推荐
5808浏览 3评论
9379浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-4-29 01:36 , Processed in 0.711227 second(s), Total 77, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号