锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

外设篇:串口通信

时间:2022-11-18 10:00:00 pc引脚插座连接器

通信涉及的几个基本概念

通信的发展历史
(1)最早通信:烽火台、狼烟;信件;电子通信(电报、电话、网络信号)
(2)通信中最重要的两个方面:信息表达和分析方法 传输信息的方法
(3)通信双方需要事先约定信息的表达方法和分析方法,否则信息无法有效传递
(4)信号传输方式是指编码后如何在传输介质上传输通信信息的过程。
结论:通信过程实际上分为三个步骤:首先,发送人根据信息编码编码有效信息(编程成可以在通信线路上传输的信号形式),然后在传输介质上传输到接收人;最后,接收人收到代码信息,获得可理解的有效信息。

同步通信和异步通信
(1)同步和异步之间的区别:首先,许多地方都有同步和异步的概念。简单地说,发送人和接收人根据同一时钟的节拍工作称为同步。发送人和接收人没有统一的时钟节拍,每个人根据自己的节拍工作称为异步。
(2)在同步通信中,通信双方按照统一的节奏工作,合作良好;一般来说,发送方需要向接收方发送信息和时钟信号,接收方根据发送方发送的时钟信号安排自己的节奏。同步通信用于固定信息交换频率或定期通信。
(3)异步通信又称异步通知。当通信频率不固定时(有时3ms收发一次,有时3天收发一次)不适合同步通信,适合异步通信。在异步通信中,接收方不必总是关心发送方。当发送方需要发送信息时,他会首先给接收方一个信息开始的开始信号。接收方收到开始信号后,认为有效信息紧随其后,开始关注接收信息,直到收到发送方发送的结束标志。

电平信号和差分信号
(1)电平信号和差分信号用于描述通信线路的传输方式。也就是说,如何在通信线路上表达1和0.
(2)电平信号传输线中有参考电平线(一般为GND),信号线上的信号值由信号线电平和参考电平线的电压差决定。
(3)差分信号的传输线没有参考电平,都是信号线。然后1和0的表达取决于信号线之间的电压差。
结论:电平信号两条通信线路之间的电平差容易受到干扰,传输容易失败;差信号不易受到干扰,传输质量相对稳定。差分信号通常用于现代通信,几乎没有电平信号。
结论2:在相同数量的通信线下,电平信号比差分信号快;但差分信号仍然很快,因为差分信号具有很强的抗干扰性,所以发送周期更短。

并行接口和串行接口
(1)串行和并行主要考虑通信线的根数,即发送人和接收人可以同时传递多少信息
(2)例如,在电平信号下,一条参考电平线 如果我们有3条线(2条信号线),一条信号线可以传递一位二进制; 1条参考线)可同时发送2位二进制;要同时发送8位二进制,需要9条线。
(3)在差分信号下,两条线(相互差分)可同时发送一位二进制;如果需要同时发送8位二进制,则需要16条线。
结论:听起来并行接口比串行接口快(串行接口只能发送一位二进制,并行接口可以发送多位二进制);但事实上,串行接口是用广泛。因为它节省了更多的信号线,而且对传输线的要求更低,成本更低;此外,通过提高通信速度,可以提高整体通信性能,不必并行。

结论:事实上,经过这么多年的发展,最终的胜利是:异步、串行、差异,如USB和网络通信。(目前使用最广泛的两种通信方式)

串口通信的基本概念和原则

串口通信的基本概念
串口通信的特点:异步、电平信号、串行
(1)异步:串口通信的发送方和接收方之间没有统一的时钟信号。
(2)电平信号:串口通信出现较早,速度较低,传输距离较近,干扰不明显,当时采用电平信号传输。后期的传输协议改为差分信号传输。
(3)串行通信:串口通信每次只能同时传输一个二进制位。

RS232电平和TTL电平
(1)电平信号由信号线电平减去参考线电平得到的电压差决定了传输值是1还是0.
(2)电平信号时多少V代表1,多少V代表0不固定,取决于电平标准。RS232电平中-3V~-15V表示1; 3~ 15V表示0;TTL电平则是 5V表示1,0V表示0.
(3)无论哪种电平都是在传输线上表示1和0。区别在于适用的环境和条件不同。RS232电平定义大,适用于干扰大、距离长的情况;TTL电平电压范围小,适用于距离近、干扰小的情况。
(4)我们台式电脑后面的串口插座是RS工业上使用串口时使用232接口,传输距离小于15米;TTL电平通常用于电路板内的两个芯片之间。
(5)编程,RS232电平传输还是TTL电平没有区别。所以电平标准对硬件工程师更有意义,软件工程师只需要稍微了解一下。TTL电平和RS232电平混电平混接)

波特率
(1)波特率(bandrate),指串口通信的速率,即串口通信时每秒可以传输多少个二进制位。例如,每秒可以传输9600个二进制位(传输一个二进制位需要1/9600秒,即104秒us),波特率就是9600.
(2)串口通信的波特率不能随意设置,而应在某些值中选择。一般最常见的波特率是9600或115200(低端单片机如51常用9600、高端单片机和嵌入式单片机SoC一般用115200).为什么波特率不能随意指定?主要原因是:首先,通信双方必须提前设置相同的波特率,以便成功通信。如果发送人和接收人根据不同的波特率进行通信,则根本无法接收。因此,波特率最好是众所周知的,而不是随机指定的。第二,经过长期发展,常用的波特率已经形成共识。常用的是9600或115200.

起始位、数据位、奇偶校准位、停止位
(1)串口通信时,收发是一个循环一个循环进行的,n个二进制位没有循环传输。这个周期叫通信单元,通信单元是由:起始位置 数据位 奇偶校验位 由停止位组成。
(2)起始位置意味着发送人应开始发送通信单元;数据位是通信单元中发送的有效信息位;奇偶验证位用于验证数据位,防止数据位错误;停止位置是发送人用来表示通信单元的结束标志。
(3)串口通信标准提前指定了起始位置的定义,反映了通信线路上的电平变化。
(4)数据位是本次通信真正需要发送的有效数据。可以设置串口通信一次发送多少有效数据(一般可选6、7、8、9、99%时,我们选择8位数据位。因为我们通常通过串口发送的文本信息是ASCII编码,而ASCII代码中的一个字符刚编码为8位。
(5)奇偶校验位用于数据位的奇偶校验(将待校验的有效数据逐个加起来,奇偶校验位总和为1,奇偶校验位总和为0),可以在一定程度上防止位反转。
(6)停止位的定义是串口通信标准提前指定的,反映了通信线路上的电平变化。常见的有一个停止位,一个.5个停止位,2个停止位等。在99%的情况下,使用1个停止位。

总结:串口通信时因为是异步通信,所以通信双方必须事先约定好通信参数,这些通信参数包括:波特率、数据位、奇偶校验位、停止位(串口通信中起始位定义是唯一的,所以一般不用选择)

串口通信的基本原理
补充通信概念:单工通信和双工通信
(1)单工是单向的,双工是双方同时收发的,但方向可以改变,称为半双工
(2)如果只能A发B收则单工,AB收或B发A收(两个方向不能同时)叫半双工,A同时发B收B发A全双工。


三条通信线:Rx Tx GND
(1)任何通信都必须有信息传输载体,或有线或无线。
(2)串口通信是有线通信,通过串口线通信。
(3)串口通信线至少需要2根(GND和信号线),可实现单工通信,也可使用3条通信线(Tx、Rx、GND)实现全双工。
(4)一般开发板都会引出SoC上串口引脚直接输出TTL电平的串口(X210开发板没有),插座用插针式插座,每个串口有三条线(Tx、Rx、GND),这些插座可以直接连接到外部TTL电平串口设备。

双方应提前规定通信参数(波特率、数据位、奇偶校准位、停止位等)
(1)串口通信属于基层基本通信规定,不会协商通信参数。通信前双方需要事先约定通信参数(一般4个最重要)
(2)串口通信的任何关键参数设置错误都会导致通信失败。比如波特率错了,发送方发送没问题,接收方也可以接收,但收到的都是乱码···

信息通过二进制流在信道上传输
(1)串口通信的发送人每隔一段时间(时间固定为1/波特率,单位为秒)将有效信息(1或0)放在通信线上,并逐一发送二进制位。
(2)接收方读取通信线上的电平,区分发送给我的是1还是0,通过定时(从读取到起始标志开始,间隔由波特率决定)。依次读取数据位、奇偶验证位、停止位,停止位意味着通信单元(帧)结束,然后中间是不确定长度的非通信时间(发送人可送第二帧,也可以长时间不发送第二帧,称为异步通信),第二帧·····
结论:首先,波特率非常重要。如果波特率错了,整个通信就会陷入混乱;数据位置、奇偶验证位置和停止位置也非常重要,否则您可能无法识别数据。第三,无论发送数字、文本、命令或什么,首先编码发送内容,编码成二进制,然后逐个发送。
(3)串口通常发送字符,通常是ASCII编码后的字符,所以数据位一般是8,方便一帧发送一个字符。

回顾:RS232电平和TTL为什么串行通信是异步的?为什么是串行而不是平行?

DB9接口介绍
(1)DB9接口是串口通信早期常用的标准化接口。
(2)串行通信是早期计算机与外部通信的主要手段。当时,计算机有一个标准的串口来实现和外部通信。当时,定义了一套标准的串口规则,DB9接口是标准接口。
(3)DB9个接口有9条通信线,其中3条非常重要GND、Tx、Rx,必不可少;剩余6根都是和流控有关的,现代我们使用串口都是用来做调试一般都禁用流控,所以这6根没用。
(4)现在一般使用串口时记得禁止流控,否则可能会出现意想不到的问题。

S5PV详细说明210串行通信接口

串口的名称
(1)S5PV210的数据手册中串口控制器在section8.1,书签搜索UART可以找到。
(2)串口的官方名称叫:universal asynchronous reciver and transmitter,通用异步收发器
英文缩写是uart,中文简称串口。


S5PV210的串口控制器工作原理框图


(1)整个串口控制器包含transmitter和receiver两部分,两部分功能彼此独立,transmitter负责210向外部发送信息,receiver负责从外部接收信息到210内部。
(2)总线角度来讲,串口控制器是接在APB总线上的。对我们编程有影响的是:将来计算串口控制器的源时钟时是以APB总线来计算的。
(3)transmitter由发送缓冲区和发送移位器构成。我们要发送信息时,首先将信息进行编码(一般用ASCII码)成二进制流,然后将一帧数据(一般是8位)写入发送缓冲区(从这里以后程序就不用管了,剩下的发送部分是硬件自动的),发送移位器会自动从发送缓冲区中读取一帧数据,然后自动移位(移位的目的是将一帧数据的各个位分别拿出来)将其发送到Tx通信线上。
(4)receiver由接收缓冲区和接收移位器构成。当有人通过串口线向我发送信息时,信息通过Rx通信线进入我的接收移位器,然后接收移位器自动移位将该二进制位保存入我的接收缓冲区,接收完一帧数据后receiver会产生一个中断给CPU,CPU收到中断后即可知道receiver接收满了一帧数据,就会来读取这帧数据。
总结:发送缓冲区和接收缓冲区是关键。发送移位器和接收移位器的工作都是自动的,不用编程控制的,所以我们写串口的代码就是:首先初始化(初始化的实质是读写寄存器)好串口控制器(包括发送控制器和接收控制器),然后要发送信息时直接写入发送缓冲区,要接收信息时直接去接收缓冲区读取即可。可见,串口底层的工作(譬如怎么移位的、譬如起始位怎么定义的、譬如TTL电平还是RS232电平等)对程序员是隐藏的,程序员不用去管。软件工程师对串口操作的接口就是发送/接收缓冲区(实质就是寄存器,操作方式就是读写内存)
(5)串口控制器中有一个波特率发生器,作用是产生串口发送/接收的节拍时钟。波特率发生器其实就是个时钟分频器,它的工作需要源时钟(APB总线来),然后内部将源时钟进行分频(软件设置寄存器来配置)得到目标时钟,然后再用这个目标时钟产生波特率(硬件自动的)。

自动流控(AFC:Auto flow control)
(1)为什么需要流控?流控的目的是让串口通信非常可靠,在发送方速率比接收方快的时候流控可以保证发送和接收不会漏掉东西。
(2)现在为什么不用流控?现在计算机之间有更好更高级(usb、internet)的通讯方式,串口已经基本被废弃了。现在串口的用途更多是SoC用来输出调试信息的。由于调试信息不是关键性信息、而且由于硬件发展串口本身速度已经相对慢的要死了,所以硬件都能协调发送和接收速率,因此流控已经失去意义了,所以现在基本都废弃了。


本来串口的功能就是上节讲过的部分,但是后来的技术发展给串口叠加了一些高级功能,在像210这类的高级SoC的串口控制器中,都有这类高级功能。


FIFO模式及其作用
(1)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这样在单片机中没什么问题,但是到复杂SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文。
(2)解决方案就是想办法扩展串口控制器的发送/接收缓冲区,譬如将发送/接收缓冲器设置为64字节,CPU一次过来直接给发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了个变相的扩展,就是FIFO。
(3)FIFO就是first in first out,先进先出。fifo其实是一种数据结构,这里这个大的缓冲区叫FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。

DMA模式及其作用
(1)DMA direct memory access,直接内存访问。DMA本来是DSP中的一种技术,DMA技术的核心就是在交换数据时不需要CPU参与,模块可以自己完成。
(2)DMA模式要解决的问题和上面FIFO模式是同一个问题,就是串口发送/接收要频繁的折腾CPU造成CPU反复切换上下文导致系统效率低下。
(3)传统的串口工作方式(无FIFO无DMA)效率是最低的,适合低端单片机;高端单片机上CPU事物繁忙所以都需要串口能够自己完成大量数据发送/接收。这时候就需要FIFO或者DMA模式。FIFO模式是一种轻量级的解决方案,DMA模式适合大量数据迸发式的发送/接收时。

IrDA模式及其用法
(1)IrDA其实就是红外,红外就是红外线通信(电视机、空调遥控器就是红外通信的)。
(2)红外通信的原理是发送方固定间隔时间向接收方发送红外信号(表示1或0)或者不发送红外信号(表示0或者1),接收方每隔固定时间去判断有无红外线信号来接收1和0.
(3)分析可知,红外通信和串口通信非常像,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。
(4)210的某个串口支持IrDA模式,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持的),然后接收方接收这些红外数据即可解码得到我们的发送信息。


串行通信与中断的关系
(1)串口通信分为发送/接收2部分。发送方一般不需要(也可以使用)中断即可完成发送,接收方必须(一般来说必须,也可以轮询方式接收)使用中断来接收。
(2)发送方可以选择使用中断,也可以选择不使用中断。使用中断的工作情景是:发送方先设置好中断并绑定一个中断处理程序,然后发送方丢一帧数据给transmitter,transmitter发送耗费一段时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成后会产生一个TXD中断,该中断会导致事先绑定的中断处理程序执行,在中断处理程序中CPU会切换回来继续给transmitter放一帧数据,然后CPU切换离开;不使用中断的工作情景是:发送方事先禁止TXD中断(当然也不需要给相应的中断处理程序了),发送方CPU给一帧数据到transmitter,然后transmitter耗费一段时间来发送这帧数据,这段时间CPU在这等着(CPU没有切换去做别的事情),待发送方发送完成后CPU再给它一帧数据继续发送直到所有数据发完。CPU是怎么知道transmitter已经发送完了?原来是有个状态寄存器,状态寄存器中有一个位叫发送缓冲区空标志,transmitter发送完成(发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来指导发送是否已经完成的。
(3)因为串口通信是异步的,异步的意思就是说发送方占主导权。也就是说发送方随时想发就能发,但是接收方如果不使用中断就只有时刻等待才不会丢失数据。所以这个差异就导致发送方可以不用中断,而接收方不得不使用中断模式。

210串行通信接口的时钟设计
(1)串口通信为什么需要时钟?因为串口通信需要一个固定的波特率,所以transmitter和receiver都需要一个时钟信号。
(2)时钟信号从哪里来?源时钟信号是外部APB总线(PCLK_PSYS,66MHz)提供给串口模块的(这就是为什么我们说串口是挂在APB总线上的),然后进到串口控制器内部后给波特率发生器(实质上是一个分频器),在波特率发生器中进行分频,分频后得到一个低频时钟,这个时钟就是给transmitter和receiver使用的。
(3)串口通信中时钟的设置主要看寄存器设置。重点的有:寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
(4)波特率发生器有2个重要寄存器:UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要的设置波特率的寄存器,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。

S5PV210串行通信编程实战

整个程序流程分析

#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);
}

(1)整个串口通信相关程序包含2部分:uart_init负责初始化串口,uart_putc负责发送一个字节

串口控制器初始化关键步骤
(1)初始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知Rx和Rx分别对应GPA0_1和GPA0_0)
(2)GPA0CON(0xE0200000),bit[3:0] = 0b0010    bit[7:4] = 0b0010    
(3)初始化这几个关键寄存器UCON0 ULCON0 UMCON0 UFCON0 UBRDIV0 UDIVSLOT0

主要的几个寄存器
(1)ULCON0 = 0x3        // 0校验位、8数据位、1停止位
(2)UCON = 0x5        // 发送和接收都是polling mode
(3)UMCON0 = 0x0        // 禁止modem、afc
(4)UFCON0 = 0x0        // 禁止FIFO模式
(5)UBRDIV0和UDIVSLOT0和波特率有关,要根据公式去算的

在C源文件中定义访问寄存器的宏
定义好了访问寄存器的宏之后,将来写代码时直接使用即可。


串口Tx、Rx对应的GPIO的初始化
给GPA0CON的相应bit位赋值为相应值,用C语言位操作来完成。

UCON、ULCON、UMCON、UFCON等主要控制寄存器
依据上节中分析的值进行依次设置即可。

波特率的计算和设置
(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) ?1
(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分
(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值

串口发送和接收函数的编写
(1)写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。

综合调试
注意Makefile的修改。

扩展练习-更改波特率后再调试
自己练习。注意程序中改了波特率后,SecureCRT也要相应修改,不然收不到东西。 

uart stdio的移植 

什么是stdio
(1)#include
(2)stdio:standard input output,标准输入输出
(3)标准输入输出就是操作系统定义的默认的输入和输出通道。一般在PC机的情况下,标准输入指的是键盘,标准输出指的是屏幕。
(4)printf函数和scanf函数可以和底层输入/输出函数绑定,然后这两个函数就可以和stdio绑定起来。也就是说我们直接调用printf函数输出,内容就会被从标准输出输出出去。
(5)在我们这里,标准输出当然不是屏幕了,而是串口。标准输出也不是键盘,而是串口。

printf函数的工作原理
(1)printf函数工作时内部实际调用了2个关键函数:一个是vsprintf函数(主要功能是格式化打印信息,最终得到纯字符串格式的打印信息等待输出),另一个就是真正的输出函数putc(操控标准输出的硬件,将信息发送出去)

移植printf函数的三种思路
(1)我们希望在我们的开发板上使用printf函数进行(串口)输出,使用scanf函数进行(串口)输入,就像在PC机上用键盘和屏幕进行输入输出一样。因此需要移植printf函数/scanf函数
(2)我们说的移植而不是编写,我们不希望自己完全从新编写而是想尽量借用也有的代码(叫移植)
(3)一般移植printf函数可以有3个途径获取printf的实现源码:最原始最原本的来源就是linux内核中的printk。难度较大、关键是麻烦;稍微简单些的方法是从uboot中移植printf;更简单的方法就是直接使用别人移植好的。
(3)我们课程中使用第三种方法,别人移植好的printf函数来自于友善之臂的Tiny210的裸机教程中提供的。

移植好的printf介绍
参考视频中讲解。

修改Makefile进行printf移植
Makefile及gcc的库文件介绍
多文件夹裸机工程的结构解析
编译运行及测试


在移植后的uart stdio项目中添加link.lds链接脚本,指定连接地址到0xd0020010

gcc可变参数及va_arg介绍
(1)printf函数中首先使用了C语言的可变参数va_start/va_arg/va_end;
(2)建议大家先去baidu“C语言可变参数”,然后按照别人的教程、博客实际写几个简单的变参的使用示例,先明白可变参数怎么工作,然后再来分析这里。

vsprintf函数详解
printf
    vsprintf
        vsnprintf
            number
vsprintf函数的作用是按照我们的printf传进去的格式化标本,对变参进行处理,然后将之格式化后缓存在一个事先分配好的缓冲区中。
printf后半段调用putc函数将缓冲区中格式化好的字符串直接输出到标准输出。

串口实验烧录问题总结 

usb下载的问题
(1)USB下载时在Win7 X64系统下,下载前面章节的小代码时没问题,下载串口通信的小代码时也没问题,下载uart stdio的移植就有问题了。有时候下载不动、有时候能下载但是不运行、有时候又正常下载运行。我已经试过下载其他的dnw或dnw驱动更新,都无法解决。

SD卡镜像烧录
(1)SD卡烧录镜像做裸机实验,在第四部分1.4.2节中有讲过。
(2)本次我们在Windows下烧录(linux下的烧录参考以前的)
(3)Windows下烧录镜像是使用九鼎提供的工具(X210光盘资料\A盘\tools\x210_Fusing_Tool.exe),注意运行时右键“以管理员身份运行”。

启动方式设置
(1)X210开发板的启动方式的选择,请参考1.2.11节。其实就是OM5的问题,OM5设置为VCC则从USB启动,OM5设置成GND,则从iNand/SD卡启动。
(2)开发板选择从iNand启动后,还要确保iNand中uboot是被擦除的。
(3)关于如何破坏uboot的问题,大家可以参考之前课程中讲的在linux/android系统中破坏uboot的方法。我之前讲过在uboot中破坏uboot的方法:movi write u-boot 0x30000000。很多同学反映擦除后错乱,进不了系统也从SD卡启动不了,只能通过USB刷机来解决。后来又分析,改为:mw 0x30000000 0x0 0x100000,然后再movi write u-boot 0x30000000
。但是反馈结果有人说可以了,有人说还是不行·······
(4)不管怎么擦除uboot,总之首先确保你的板子SD卡启动是成功的。怎么确保?先用SD卡烧录启动之前的LED闪烁的项目,确保看到现象就证明烧录SD卡方法和启动SD卡都成功了,再做本节课的实验。

链接脚本的影响
bin文件大于16KB怎么办?
通过USB下载最多也只能下载96KB大小的bin,如果bin大于96KB肯定SRAM放不下会出错。如果用SD卡启动,那么mkv210_image.c决定了bin文件最大不能超过16KB。
超过了怎么办?2种解法:
第一,在USB下载时,可以先下载一个x210_usb.bin,然后再将裸机程序连接到0x23E00000,然后再修改dnw中下载地址,将裸机代码下载到0x23E00000运行。(这时不需要重定位了)
第二,在SD卡启动时,将整个裸机工程分为2部分;第一部分大小16KB以内,第二部分放剩下的(放在SD卡的后面的某个扇区开始的位置,譬如放在第50个扇区开始的位置),然后在裸机代码中进行重定位(SD卡中重定位)。这个暂时没讲,以后如果有用到就讲。 

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章