基于多单片机的串口扩展设计论文[5篇材料]

时间:2019-11-17 01:08:06下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《基于多单片机的串口扩展设计论文》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《基于多单片机的串口扩展设计论文》。

第一篇:基于多单片机的串口扩展设计论文

前言

笔者在用单片机开发一款称重仪表时,功能较多,对串口的需求很高。需要的串口数量多,至少要五个串口,包括称重传感器通信串口,电脑上位机通信串口,GIM900A 通信串口,大屏幕数码管显示的通信串口,打印模块的通信串口等。而且对串口要求稳定性高,大部分串口都要求实时双工通信。根据实际情况和产品串口需求,采用不用的方法进行串口扩展,主要用到了模拟串口和多单片机实现串口扩展。串口扩展的一般方法

(1)模拟串口。模拟串口利用其他单片机引脚模拟串口收发时序进行串口扩展。这种串口扩展,缺点比较明显,通信速率慢,可靠性不高,占用CPU 资源较多。高速双工通信时一般不用此方案进行串口扩展,低速情况下可以考虑。笔者的项目中大屏幕数码管显示就用了这种方案,显示的时候只发不收,单向通信,波特率要求低,最高不过9600bps。

(2)利用专门的串口扩展芯片处理。串口扩展芯片进行串口扩展,通信稳定性高,能达到一般的串口要求。市场上的串口扩展芯片,性能不同,价格也不一样,但普遍成本较高,少则二三十元,多则七八十元,不利于产品的成本控制。串口需求较多时,一块串口扩展芯片上串口数量不足,还需要多块串口扩展芯片级联,更增加了成本。

(3)利用多串口单片机。目前市场上有多串口的单片机,很多低成本单片机都自带两个串口,比如stc12 多串口系列。用三串口及其以上的单片机成本更贵。

(4)基于多单片机的串口扩展设计。在一定成本要求下,结合目前单片机产品自身的优势,利用多单片机进行串口扩展,也是一种串口扩展的方案。一般c51 系列单片机自带双串口的只要几元钱,完全可以把单片机用来做串口扩展,而且有的单片机自带spi 通信接口,可以很方便的实现主从单片机之间的级联和通信,同时双单片机工作时,可以利用从单片机处理一定的程序,减轻主单片机的负担,达到“双核”效果。基于多单片机的串口扩展设计

3.1 串口扩展系统框图

整个系统由两块单片机构成主从结构,主机完成产品的大部分功能,从机只是进行了串口扩展,扩展出了两个双工硬件串口,如果有需要,也可以分担部分主机的其他功能。两者之间通过SPI 硬件接口通信,该硬件SPI 总线是一种全双工、高速、同步的通信总线,支持主模式和从模式两种操作模式,主模式中支持高达3Mbps 的速率,完全可以完成主机和从机之间的可靠通信。主机和从机的串口通信,和一块单片机使用时的用法一样,只是先要经过SPI 传输。当需要向从机串口发数据时,先要通过主机的SPI 通信送给从机,再通过从机串口发给外围模块;当需要接收从机串口数据时,先从机接收到串口数据,从机再利用SPI 传输给主机。在进行软件开发时,只要定义好主机和从机的SPI 通信协议,即可完成可靠的串口数据收发。

3.2 主机和从机之间的SPI 通信

主机和从机串口之间需要SPI 通信做桥梁,因此主从机之间的SPI 通信显得极其重要,必须要求高速、可靠、实时,一次SPI 采用中断完成。主机部分需要用到常用的四个函数,即主机SPI 初始化,SPI 主从机之间的数据交换,向从机发送数据,主机SPI 中断接收等。

1)主机SPI 初始化:

SPDAT=0;

SPCTL=0xfd;

SPSTAT=0xc0;

IE2=IE2 | 0x2;

2)主机SPI 数据交换

SPDAT = dat;

while(!(SPSTAT & SPI_SPIF));

SPSTAT = 0xc0;

return SPDAT;

3)向从机发送字符串数据

SPCTL = 0xfd;

IE2=IE2 & 0x01;

SPISS=0;

4)SPI 接收中断函数

uchar ucRecvSpi;

SPDAT=SPDAT;

SPSTAT = 0xc0;

ucRecvSpi=SPDAT;

??//SPI 接收到的数据处理

?循环SPI 数据交换

发送字符串

SPISS=1;

SPCTL = 0xec;

IE2=IE2 | 0x3;

从机部分也需要用到主机一样的四个函数,即从机SPI 初始化,SPI 主从机之间的数据交换,向主机发送数据,从机SPI中断接收等。程序函数与主机大部分相同,只有细微区别。在从机SPI 初始化时,SPCTL 控制寄存器初值为0xec。

3.3 扩展的串口处理

从机自带的两个双工串口即是扩展出来的串口,要实现收发数据,需要用到基本的3 个函数,即从机串口初始化,从机串口向外围模块发送数据,从机中断接收数据。串口4 和串口5 函数类似,下面只列举串口4 的初始化函数部分。

1)串口1 初始化

TMOD = 0x20;

SCON = 0x5a;

TH1 =TL1=-3;

TR1 = 1;

ES = 1;EA = 1;

2)串口接收中断

RI = 0;

Buf[i]=SBUF;// 接收串口数据存入数组

if(SBUF==0x0a && Buf[i-2]==0x0d)

接收到结束符,则向主机发送串口数据。结语

本文中的串口扩展方法,实用性强,成本较低,能较好的实现串口扩展,同时利用多出的单片机,可以为主CPU 分担一定的任务,提供一定的硬件资源。

第二篇:单片机串口总结

51单片机串口总结

有句话说“尽信书不如无书”,要学好单片机就要不断的、大胆的实验,要多怀疑,即使我们的怀疑最终被证明是错误的那么这也是进步(人们认识事物很多情况下来源于怀疑),当怀疑出现时就要去实践。有很多东西如果不通过实践是不可能掌握其中隐藏的奥秘,就拿51单片机串口通讯这一块,我认为掌握很好了,可以很轻松的实现数据的接收、发送,但这段时间当我重新学习串口时,我才发现里面还有很多小细节从没注意,更别说研究了。对于接收发送程序永远是按照别人的模式来编写程序,并没有真真正正的挖掘深层次的内容。我身边太多的人在临摹别人的程序,当然我不反对,但是希望自己多问几个问什么,单纯的会编程是学不好单片机的,毕竟单片机有自己独特的硬件结构。

开讲之前先简要说一下同步、异步通信:

同步通信:发送方时钟对接收方时钟控制,使双方达到完全同步。

异步通信:发送与接受设备使用各自的时钟控制数据的发送和接受过程(虽然时钟不同,但一般相差不大)。

51单片机串行口结构

从上图中我们看到,51单片机有两个物理上独立的接收、发送缓冲器SBUF,它们共用同一个地址99H,但是请注意:接收缓冲器只能读而不能写,发送缓冲器只写不读。单片机可以同时实现数据的发送与接收功能。

特别注意:接收器是双缓冲结构:当前一个字节从接收缓冲区取走之前,就已经开始接收第

二个字节(串行输入至移位寄存器),此时如果在第二个字节接收完毕而前一个字节还未被读走,那么就会丢失前一个字节。

51单片机串口控制寄存器

关于51单片机的控制寄存器各个位表示的含义在这里我只谈SM2。

SM2为多机控制位,主要用于工作方式2和3,当接收机的SM2=1时,可以利用接收到的RB8来控制是否激活RI(RB8=0不激活RI,收到的数据丢失;RB8=1时收到的数据进入SBUF,并激活RI ,进而在中断服务程序中将数据从SBUF中读走)。当SM2=0时,不论收到的RB8为何值都将使接收到的数据进入SBUF,并激活RI,通过控制SM2实现多机通信。

51单片机串口通讯方式

51串口通讯方式有3种,方式0、方式

1、方式2与方式3,他们的工作模式不尽相同。首先他们的波特率很容易忽视。方式0与方式2的波特率固定,而方式1和3的波特率由T1的溢出率决定。

方式0的波特率=f/12

系统晶振的12分频,换句话说12M晶振的情况下,其波特率可达1M,速度是很高的(当我们在选用串行器件并采用方式0时需要特别注意器件所能允许的最大时钟频率)。

方式2 =f/64或f/32(当SMOD=1时为f/32,SMOD=0时为f/64)。

曾经我用方式2进行MODBUS通信时,总是通讯失败,我仔细检查程序,没有发现逻辑错误,特别是当我参考别人的程序时,发现很少有人用方式2进行MODBUS通讯,所以当时自己妄下结论51单片机的串行方式2不可用,直到有一天夜里我突然想起方式2的波特率是固定的,试想晶振11.0592M/32或11.0592M/64怎么也不可能是9600啊,怎么可能通信成功。这才恍然大悟,看来还是自己太武断了,没有认真看书啊。有时我们认为我们犯这样的错误很低级,其实我们很多次都是因为这样的小细节导致我们整个系统不正常,正所谓“千里之堤毁于蚁穴”,这些细节真的伤不起啊。

方式1、3波特率=(2smod/32)*T1的溢出率,其中TI的溢出率=f/{12*[256-(TH1)]}.关于3种通讯方式其中有几点特别容易出错:

1、无论采用哪种通讯方式,数据发送和接受都是低位在先,高位在后。、3种方式作为输出,由于输出是CPU主动发送,不会产生重叠错误,当数据写入SBUF后,发送便启动(通过单片机内部逻辑控制,与程序无关),当该字节发送结束(SBUF空),置TI。不要理解为当数据一写入SBUF就置位TI,如果中断允许则在中断中发送数据,这就大错特错了。同样作为输入,可能会产生重叠错误(主要依赖于特定的环境),当一个字节的数据接收完毕(SBUF满)置位RI,表示缓冲区有数据提示CPU读取。

接下来通过一些实验具体说明串口通信中需要注意的地方 方式0输出

方式0主要功能是作为移位寄存器,将数据从SBUF中逐位移出,最常见的用法就是外接串入并出的移位寄存器,如74LS164。之前在做这一部分实验时总是利用单片机I/O端口模拟实现,现在想想在串口未被占用的情况下,方式0是最好的实现方式。

利用串口方式0,向74LS164输出字符“0”的编码,程序如下:

该程序采用了中断方式实现,结果是通过74LS164使数码管显示“0”。实验结果如下:

这里我说明几点: 如果采用查询方式,并且只发送一遍,那么程序最后的while(1);不可以省略,否则会出现数码管闪烁的现象(在KEIL环境下,main()函数也是作为一个调用函数,最后也有返回RET,它不像C中的main()函数,当执行完毕后就停止,而是重新复位执行,如此反复,这一点要特别注意)

这是查询方式下不加while(1);的现实效果 如果采用中断方式发送,请记得中断中清除TI,仅仅是为了解除中断标志,而不是等待发送结束,因为此时数据早已离开了SBUF跑到外边去了。3 74LS164最高25MHZ,采用方式0,没有问题。

方式0作为输入模式

以74ls165(最高时钟25MHZ)为例,可以满足要求。

对应结果如下:

(注意:74ls165线传送高位,而串口通信低位在先,所以显示的数据和实际数据高低位正好相反

P1.7---P1.0对应D0---D7)。

本程序只接收一次,也许有人会问,中断程序中REN=0,表示什么意思?可不可以改成ES=0?

这个问题很好,首先REN=0表示接收禁止,即不允许串口接收数据;ES=0是禁止中断和单片机是否接收数据没有关系,不接收数据自然中断允许也是徒劳,这两者有很大的区别。我们在很多接收程序中经常可以看到在判断RI标志后紧跟着清除标志位,我想问一下,为什么?)

如果我们也按照这种模式改写会怎样呢?

实验结果如下

两次结果差异怎么这么大?为什么会这样子?

为了便于理解,也为了说明问题方便,对中断程序做了如下处理:

结果又变了

是不是感觉很奇怪,究竟咋回事呢?

首先中断程序中当判断RI置位标志后紧跟着清零是为了接收下一个字节的数据,也为了避免单片机重复中断。

当51单片机串口方式0作输入时,在REN=1且RI=0的条件下就启动了单片机串口接收过程。如果有一个条件不满足就不能启动接收过程,以上出现的错误正式由于忽略了这个重要的因素造成的。在RI清零后由于REN仍然为1,单片机已经开始接收第二字节的数据,由于串口速度很快,RI仍会置位,而紧接着将REN清零只能阻止单片机接收数据,但是却

不能阻挡第二次中断。由于只接收了部分外部引脚数据(此时外部引脚为高电平,即逻辑1,其实单片机只接收了一位,对于12M晶振而言,方式0大约8us接收一个字节数据)。相反在RI=0与REN=0之间加上适当的延迟,就可以保证一个字节的数据全部接收完毕,故此时我们读上来的一个字节为0xff。

我在中断程序中添加了一个中断计数器(不加延迟),发现中断服务程序的确执行了两次

结果如下

加上延迟结果

这就验证了刚才的结论。

至于说可不可以换做ES=0,回答是可以的,尽管同样可以实现数据的读取,但是实质不同,当禁止中断后,单片机仍在接收外部数据,只是不再请求中断,自然的不再读取第2、3。。。字节的数据,那么P1将保留第一次中断时从SBUF中读出的数据。如果某一时刻打开中断发现结果不正常,如果理解了上面的机制就不会觉得惊讶了。建议:单次接收时,中断服务程序中REN清零放在RI之前。

还有一个问题非常重要:

如果我在中断服务程序中不清除RI,会怎样?

很少有人会这样用,但是经常有人忘记了(包括我)。课本上写得很清楚,务必在中断中用软件清除RI,为什么要这样呢?难道仅仅是为了接收下一次数据并且避免单片机不断的响应中断?的确如此,如果对于一个小系统而言,不清除中断标志,那么单片机将不停的中断,影响接下来任务的执行,系统必然瘫痪,而且不能正常的接收数据。总结:方式0作为发送方,只要向SBUF中写入数据就启动了发送过程;

方式0在座位接收模式时,REN=

1、RI=0的情况下就已经启动了接收过程。在中断程序中要注意两者清零的顺序。

还有一种情况要特别注意:单片机复位时SCON自动清零,如果单片机不工作在方式0,那么如果采用位操作SCON时也要注意REN=1与SM0、SM1的书写顺序,总之切记方式0启动发送、接收数据的条件。

方式1 方式1为10位异步通信模式。作为输出和方式0没有本质的区别,不同的是数据帧的形式,但是对于接受模式则有点不同,当REN=1且RI=0时,单片机并不启动接收过程。而是以已选择波特率的16倍速率采样RXD引脚的电平,当检测到输入引脚发生1---0负跳变时,则说明起始位有效,才开始接受本帧数据。方式1模式下 单片机可以工作在全双工以及半双工方式。下面举两个例子

半双工

主机发送某一字符,从机接收到数据后返回数据加1的值 比如 主机发送“1“,从机收到后回复主机”2“。实验结果如下:

方式1工作方式主要注意: 1 波特率可变。数据接收以起始位为标志,停止位结束。当RI=0且SM2=0或接收到有效停止位时,单片机将接收到的数据移入SBUF中,两个条件缺一不可。

方式2和方式3 方式2和3不同的只是波特率,这里以方式3为例

作为输出模式同方式1没有区别,只是增加了第八位数据位,第八位数据可以用作校验位或在多机通信中用作数据/地址帧的判别位。

首先我们来做模拟主从奇偶校验模式

主机发送一帧数据,并发送奇偶校验位,从机接收数据后,判断数据是否正确,如果正

确,接收指示灯亮,并且回送主机数据加1,反之回送0;主机接收从机信息,如果校验正确点亮LED指示灯.(从机、主机接收数据无论校验正确与否,均显示接收到的字节数据)。奇校验模式 演示结果如下:

(注:从接接收不正确,返回0)

主从机接收正确效果

之前我们已经介绍了SM2的具体用法,主要用于多机通信,将SM2作为数据/地址帧 的判别位,在接收地址时令SM2=1,当接收到的第八位数据为1时激活RI产生中断,然后比较地址,如果地址符合则清除SM2准备接受数据信息,反之不理睬。

特别注意 当RI=0且SM2=0(或SM2=1时接收到第9位数据为1)时,单片机将接收到的数据移入SBUF中,两个条件缺一不可。

在这里我只举一个简单的例子 一个主机,两个从机 起始时,主机从机的SM2均置位,所有的从机等待主机发送地址帧,主机令TB8=1,发送地址帧。所用的从机将接受到的地址和自己的地址比较,如果符合,点亮LED指示灯,清除SM2(准备接受主机发送的数据帧),并将自己的地址发送到主机。主机接收从机发送的地址信息,如果地址符合则数码管显示从机地址并开始准备发送数据,反之发复位信号,TB8=1。从机接收数据先判断RB8,如果RB8=1,则复位,重新开始接收主机发送的地址帧,反之通过P1口外接数码管显示接收到的数据。实验结果如下:

注意:如果主机没有得到正确的地址,则将按照一定的速率发送地址帧,直到接收正确的地址为止,该试验主机向从机2发送信息。

另外在这里我补充两点: 我们可以很方便的利用串口通信的工作方式2或3实现奇偶校验,注意技巧,当为偶校验时TB8=P,奇校验时TB8=~P;

2当单片机利用中断发送大量数据时,尽量采用中断发送,因为单片机在写入SBUF数据后由硬件将数据发送完,在发送过程中,单片机还可以做很多事情,利用中断发送数据可以提高CPU利用率。尤其在低波特率时效果更明显。

第三篇:单片机串口通信方式总结

IIC总线通信协议————数据传输高位在前p233 1,起始和停止条件

开始信号:SCL为高电平,SDA由高电平向低电平跳变,开始传送数据。void start()// 开始位 { SDA = 1;

//SDA初始化为高电平“1”

SCL = 1;

//开始数据传送时,要求SCL为高电平“1”

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SDA = 0;

//SDA的下降沿被认为是开始信号

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SCL = 0;

//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)} 结束信号:SCL为高电平,SDA由低电平向高电平跳变,结束传送数据。void stop()// 停止位 { SDA = 0;

//SDA初始化为低电平“0”

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SCL = 1;

//结束数据传送时,要求SCL为高电平“1”

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SDA = 1;

//SDA的上升沿被认为是结束信号 }

2,数据格式(数据输入)

在IIC总线开始信号后,送出的第一个字节数据是用来选择器件地址和数据方向的,其格式为

从器件收到地址型号后与自己的地址比较,一致则此器件就是主器件要找的器件,并返回ACK(不管是写数据还是地址都会返回)。IIC传送数据时SCL为低电平时SDA可改变高低电平,SCL转跳为高时数据输入(此时SDA不能跳变),发送数据:bit WriteCurrent(unsigned char y){ unsigned char i;bit ack_bit;

//储存应答位

for(i = 0;i < 8;i++)// 循环移入8个位

{

SDA =(bit)(y&0x80);

//通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

_nop_();

//等待一个机器周期

SCL = 1;

//在SCL的上升沿将数据写入AT24Cxx

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SCL = 0;

//将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲

y <<= 1;

//将y中的各二进位向左移一位

} SDA = 1;

// 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,//以让SDA线转由接收设备(AT24Cxx)控制

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

SCL = 1;

//根据上述规定,SCL应为高电平

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

_nop_();

//等待一个机器周期

ack_bit = SDA;//接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节

//若送高电平,表示没有接收到,传送异常

SCL = 0;

//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)

return ack_bit;

// 返回AT24Cxx应答位 } 读数据:unsigned char ReadData()// 从AT24Cxx移入数据到MCU { unsigned char i;unsigned char x;

//储存从AT24Cxx中读出的数据

for(i = 0;i < 8;i++){

SCL = 1;

//SCL置为高电平

x<<=1;

//将x中的各二进位向左移一位

x|=(unsigned char)SDA;//将SDA上的数据通过按位“或“运算存入x中

SCL = 0;

//在SCL的下降沿读出数据

} return(x);

//将读取的数据返回 } 发送数据步骤:

oid WriteSet(unsigned char add, unsigned char dat)// 在指定地址addr处写入数据WriteCurrent { start();

//开始数据传递

WriteCurrent(OP_WRITE);//选择要操作的AT24Cxx芯片,并告知要对其写入数据

WriteCurrent(add);

//写入指定地址

WriteCurrent(dat);

//向当前地址(上面指定的地址)写入数据

stop();

//停止数据传递

delaynms(4);

//1个字节的写入周期为1ms, 最好延时1ms以上 } 读数据步骤:

/*************************************************** 函数功能:从AT24Cxx中的当前地址读取数据 出口参数:x(储存读出的数据)

***************************************************/ unsigned char ReadCurrent(){ unsigned char x;start();

//开始数据传递

WriteCurrent(OP_READ);

//选择要操作的AT24Cxx芯片,并告知要读其数据

x=ReadData();

//将读取的数据存入x stop();

//停止数据传递

return x;

//返回读取的数据 } /*************************************************** 函数功能:从AT24Cxx中的指定地址读取数据 入口参数:set_add 出口参数:x

***************************************************/ unsigned char ReadSet(unsigned char set_add)// 在指定地址读取 { start();

//开始数据传递

WriteCurrent(OP_WRITE);

//选择要操作的AT24Cxx芯片,并告知要对其写入数据

WriteCurrent(set_add);

//写入指定地址

return(ReadCurrent());

//从指定地址读出数据并返回 }

单总线协议————数据传输低位在前——p237 1,初始化单总线器件

初始化时序程序:

函数功能:将DS18B20传感器初始化,读取应答信号 出口参数:flag

***************************************************/ bit Init_DS18B20(void){ bit flag;

//储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在

DQ = 1;

//先将数据线拉高

for(time=0;time<2;time++)//略微延时约6微秒

;DQ = 0;

//再将数据线从高拉低,要求保持480~960us for(time=0;time<200;time++)//略微延时约600微秒

;

//以向DS18B20发出一持续480~960us的低电平复位脉冲

DQ = 1;

//释放数据线(将数据线拉高)

for(time=0;time<10;time++)

;//延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲)

flag=DQ;

//让单片机检测是否输出了存在脉冲(DQ=0表示存在)

for(time=0;time<200;time++)//延时足够长时间,等待存在脉冲输出完毕

;return(flag);

//返回检测成功标志 }

单总线通信协议中存在两种写时隙:写0写1。主机采用写1时隙向从机写入1,而写0时隙向从机写入0。所有写时隙至少要60us,且在两次独立的写时隙之间至少要1us的恢复时间。两种写时隙均起始于主机拉低数据总线。产生1时隙的方式:主机拉低总线后,接着必须在15us之内释放总线,由上拉电阻将总线拉至高电平;产生写0时隙的方式为在主机拉低后,只需要在整个时隙间保持低电平即可(至少60us)。在写时隙开始后15~60us期间,单总线器件采样总电平状态。如果在此期间采样值为高电平,则逻辑1被写入器件;如果为0,写入逻辑0。

下图为写时隙(包括1和0)时序

上图中黑色实线代表系统主机拉低总线,黑色虚线代表上拉电阻将总线拉高。下面是代码:

WriteOneChar(unsigned char dat){ unsigned char i=0;for(i=0;i<8;i++)

{

DQ =1;

// 先将数据线拉高

_nop_();

//等待一个机器周期

DQ=0;

//将数据线从高拉低时即启动写时序

DQ=dat&0x01;

//利用与运算取出要写的某位二进制数据,//并将其送到数据线上等待DS18B20采样

for(time=0;time<10;time++)

;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样

DQ=1;

//释放数据线

for(time=0;time<1;time++)

;//延时3us,两个写时序间至少需要1us的恢复期

dat>>=1;

//将dat中的各二进制位数据右移1位

}

for(time=0;time<4;time++)

;//稍作延时,给硬件一点反应时间 }

对于读时隙,单总线器件仅在主机发出读时隙时,才向主机传输数据。所有主机发出读数据命令后,必须马上产生读时隙,以便从机能够传输数据。所有读时隙至少需要60us,且在两次独立的读时隙之间至少需要1us恢复时间。每个读时隙都由主机发起,至少拉低总线1us。在主机发出读时隙后,单总线器件才开始在总线上发送1或0。若从机发送1,则保持总线为高电平;若发出0,则拉低总线。

当发送0时,从机在读时隙结束后释放总线,由上拉电阻将总线拉回至空闲高电平状态。从机发出的数据在起始时隙之后,保持有效时间15us,因此主机在读时隙期间必须释放总线,并且在时隙起始后的15us之内采样总线状态。

下图给出读时隙(包括0或1)时序

图中黑色实线代表系统主机拉低总线,灰色实线代表总局拉低总线,而黑色的虚线则代表上拉电阻总线拉高。代码为:

unsigned char ReadOneChar(void){

unsigned char i=0;

unsigned char dat;//储存读出的一个字节数据

for(i=0;i<8;i++)

{

DQ =1;

// 先将数据线拉高

_nop_();

//等待一个机器周期

DQ = 0;

//单片机从DS18B20读书据时,将数据线从高拉低即启动读时序

dat>>=1;

_nop_();

//等待一个机器周期

DQ = 1;

//将数据线“人为”拉高,为单片机检测DS18B20的输出电平作准备

for(time=0;time<2;time++)

;

//延时约6us,使主机在15us内采样

if(DQ==1)

dat|=0x80;//如果读到的数据是1,则将1存入dat

else

dat|=0x00;//如果读到的数据是0,则将0存入dat

//将单片机检测到的电平信号DQ存入r[i]

for(time=0;time<8;time++)

;

//延时3us,两个读时序之间必须有大于1us的恢复期

}

return(dat);

//返回读出的十进制数据 }

每个单总线器件内部都光刻了一个全球唯一的64位二进制序列码,用于该单总线器件的识别

SPI总线协议

SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。

SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。

上升沿发送、下降沿接收、高位先发送。

上升沿到来的时候,sdo上的电平将被发送到从设备的寄存器中。

下降沿到来的时候,sdi上的电平将被接收到主设备的寄存器中。读代码:

unsigned char ReadCurrent(void){

unsigned char i;unsigned char x=0x00;

//储存从X5045中读出的数据

SCK=1;

//将SCK置于已知的高电平状态

for(i = 0;i < 8;i++){

SCK=1;

//拉高SCK

SCK=0;

//在SCK的下降沿输出数据

x<<=1;//将x中的各二进位向左移一位,因为首先读出的是字节的最高位数据

x|=(unsigned char)SO;//将SO上的数据通过按位“或“运算存入 x

} return(x);

//将读取的数据返回

} 写代码:

void WriteCurrent(unsigned char dat){

unsigned char i;SCK=0;

//将SCK置于已知的低电平状态

for(i = 0;i < 8;i++)// 循环移入8个位

{

SI=(bit)(dat&0x80);

//通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

SCK=0;

SCK=1;

//在SCK上升沿写入数据

dat<<=1;

//将y中的各二进位向左移一位,因为首先写入的是字节的最高位

} } RS232通讯协议 串行通讯方式3 RS485通讯协议 串行通讯方式1

第四篇:STC单片机串口在线烧录芯片问题总结

STC单片机串口在线烧录芯片问题总结

在一个偶然和朋友聊天中了解了STC单片机芯片,从此一发不可收拾。当时我看中STC芯片的一个主要原因是因为它有AD转换功能和在线烧录功能。用到现在算起来也大致有三、四年的时间了,在此期间用了不少STC不同型号的芯片。总的来讲这个芯片还是比较好使的,但在烧录过程中也碰到不少麻烦,现在把它罗列如下,以便和同行们一起交流、探讨和学习。

第一种情况是通过USB转串口烧录。曾经成功过一段时间,但后来不知道为什么再也烧录不进去了,直到现在也不明白其中的道理。查了一些资料说是USB转串口的芯片问题,需要专用芯片的USB转串口。我也信了,但从此给我的印象是-------STC单片机烧录程序时是要挑芯片的。

第二种情况是串口烧录时有些232芯片不好用,一打听才知道是232芯片不好,不能用国产的要用进口的,我又专门去买了一批7元多一片的进口232芯片,结果-------没有成功过。不得已只好换回用国产的,哎!好了,谢天谢地!阿弥多佛!看来STC芯片串口在线烧录不但挑USB转串口的芯片,还挑232芯片。

第三种情况是同一批板子、同一批232芯片有些板子能在线烧录程序,而有些板子却不能烧录程序,实在没办法。还好本次产品是采用PLCC封装的,只好把不能烧录的芯片拔到可以烧录的板子上去烧录好再拔插回去,说到这里有人可能会怀疑不能烧录的板子232芯片或外围电路有问题,我当时的直觉也是这样的,但是我板子232口只要烧录好程序,工作时通讯一切正常,这又作何解释?不可思议!

第四种情况(也是我偶然发现的)5v的STC15F104E芯片,有时候能烧录,有时候不能烧录,不能烧录的概率在90%以上,真是莫名其妙。摸索了将近一天时间才发现串口接上后(板子在没有上电的时候)STC芯片电源脚有约3v电压,我想想可能是从串口反串回来的,有这3v电压的存在,芯片就如同没有掉电,所以也就烧录不进去。我就用镊子把电源到地短接一下,目的是进行放电。然后马上给板子上电,哎~~~成了!并且屡试不爽。有类似情况的朋友也不妨一试。哈。。

第五种情况是我有一批板子用的是STC12LE5A60S2 QFP44封装,在我的笔记本上用串口烧录成功率为100%,而到我台式机上用串口烧录时成功率却为0%,是我台机的串口有问题吗?非也!台机串口烧录STC15F104E和其它是好的,但是对付本批次板却是无计可施,最后无论我如何绞尽脑汁也不得其解,只好怀疑是板子在设计时有问题,但是设计有问题的板子为什么在笔记本上烧录又是好的呢?只能说-------STC芯片串口在线烧录不但挑USB转串口的芯片、挑232芯片,还挑电脑。

第六种情况是同一块板子今天能烧录进去,过一段时间又烧录不进去了,再放一段时间又能烧录进去了。唉~~~看来STC芯片串口在线烧录不但挑USB转串口的芯片、挑232芯片、挑电脑,还要看它的心情。

我晕!STC的芯片真的是让人欢喜让人忧。

第五篇:linux串口触摸屏设计总结

Linux serial touch 设计总结

概述:

最近在做嵌入式linux下串口触摸屏设计,遇到一些问题,经过查找资料和请教同事,总算把问题解决了,事后有把linux相关的内核代码仔细看了一遍,为了有点成果,特别写了个总结。如有任何问题请联系yxj_5421@163.com,转载请标明出处。

系统资源:

Linux:2.6.36

UI:QT+TSLIB 硬件资源不关心

设计方法:

有两种实现途径。

1、是将要使用的串口单独拿出来,作为一个platform总线设备实现,在嵌入式平台mach文件里面,加上串口中断号和寄存器首地址,然后将这个串口注册成一个platform总线设备。在驱动probe函数里面需要得到这个串口中断号以及寄存器映射地址,通过寄存器映射地址设置串口波特率,数据位,停止位等,通过中断号注册中断等,然后调用input_register_device注册一个input设备。在中断里面得到外面触摸屏的数据,然后根据input touch协议上报触摸数据。这种方法实现简单明了,不需要和linux的tty,serio等打交道。但是要求知道串口硬件spec,比如寄存器等,而且这个串口就只能给触摸屏使用了,不能作为tty使用。因为是嵌入式开发,因此很容易知道硬件spec,而且嵌入式平台一旦确定,那么这个串口肯定就是给触摸屏使用了。因此在嵌入式平台上,推荐使用这个方法。

是将串口作为一个serio总线设备,利用linux内核提供serio总线驱动,通过设置对应的串口,调用serport提供的函数将串口当做serio总线设备,在驱动里面需要按照serio总线设备驱动的框架来实现,这方面的例子linux里面有很多,比如touchright.c,在模块init函数里面调用serio_register_driver注册serio总线设备驱动,如果serio总线上对应的serio设备存在,就调用connect函数,在这个函数里面调用input_register_device注册一个input设备。具体驱动不再分析了,很简单,相信各位都能看的懂。

至此,两种方法都实现了串口触摸屏的驱动,讲到这里是不是就完了,非也,本文的重点还在后面,请看下面分析:

第一种方法只要驱动模块被加载,就会在/dev/input下面创建一个eventx节点,tslib就能访问这个节点,获得触摸坐标,然后送给qt。第二种方法驱动模块加载后,并没有创建eventx节点,也就是说connect函数没有被调用,按照linux驱动模型来看,就是serio总线上还没有对应的serio设备,因此驱动加载时没有对应的设备,就不会调用connect函数,这时的串口还是作为一个linux tty设备存在。

我遇到的问题就是serio驱动加载了,但是没有创建eventx节点,查找资料也只有一个说是要把tty设置成N_MOUSE,然后读,说的不清楚,也不知道怎么实现,经过自己摸索,终于把问题解决了。

2、Linux 启动后串口形式: Linux一启动是将串口作为tty来设置的。看下的调用:

start_kernel

init/main.c大家对这个函数不陌生吧,linux启动过程中重要的一个函数

console_init();

drivers/tty/tty_io.c

tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);drivers/tty/tty_idisc.c 给串口注册一个tty链路层处理函数ops。

现在我们需要写一个上层的应用程序,对这个tty进行设置,需要设置波特率,数据位,停止位等,最重要的是要将这个tty设备设置成一个serio总线设备,然后把它注册在serio总线上,请看下面的代码:

fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);

if(fd < 0){

setline(fd, type->flags, type->speed);ldisc = N_MOUSE;if(ioctl(fd, TIOCSETD, &ldisc)){

} fprintf(stderr, “inputattach: can't set line disciplinen”);return EXIT_FAILURE;

} fprintf(stderr, “inputattach: '%s'-%sn”, device, strerror(errno));return 1;

里面的device就是对应要使用的那个串口,linux里面一般是/dev/ttyS0,首先是打开串口 open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)接着设置波特率等 setline(fd, CS8, B9600);static void setline(int fd, int flags, int speed){

} struct termios t;tcgetattr(fd, &t);t.c_cflag = flags | CREAD | HUPCL | CLOCAL;t.c_iflag = IGNBRK | IGNPAR;t.c_oflag = 0;t.c_lflag = 0;t.c_cc[VMIN ] = 1;t.c_cc[VTIME] = 0;cfsetispeed(&t, speed);cfsetospeed(&t, speed);tcsetattr(fd, TCSANOW, &t);devt = type->type |(id << 8)|(extra << 16);if(ioctl(fd, SPIOCSTYPE, &devt)){ fprintf(stderr, “inputattach: can't set device typen”);} return EXIT_FAILURE;

read(fd, NULL, 0);

接下来就是重点了

ldisc = N_MOUSE;if(ioctl(fd, TIOCSETD, &ldisc))

跟踪代码到内核层ioctl:

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

drivers/tty/tty_io.c case TIOCSETD: return tiocsetd(tty, p);

drivers/tty/tty_io.c

tty_set_ldisc(tty, ldisc);drivers/tty/tty_idisc.c,ldisc等于N_MOUSE new_ldisc = tty_ldisc_get(ldisc);

ldops = get_ldops(disc);

这段代码需要得到N_MOUSE的链路层,先在tty_ldiscs里面查找是否有N_MOUSE链路层的处理函数ops,如果没有,就需要加载serport模块,看看这个模块init函数 retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);注册一个N_MOUSE链路层的处理函数ops 创建一个新的N_MOUSE链路层new_ldisc,接着调用 tty_ldisc_assign(tty, new_ldisc);

把新的链路层放在tty里面 retval = tty_ldisc_open(tty, new_ldisc);打开这个新的链路层

至此,已经给串口增加了一个N_MOUSE的链路层,并且把链路层的处理函数也注册进去了。这个串口当前的链路层就是N_MOUSE。目前为止串口还只是个tty设备,并没有注册到serio总线上。继续看我们的应用程序:

devt = type->type |(id << 8)|(extra << 16);if(ioctl(fd, SPIOCSTYPE, &devt)){

fprintf(stderr, “inputattach: can't set device typen”);

return EXIT_FAILURE;} ret = ld->ops->open(tty)

ld->ops就是serport注册的serport_ldisc static int serport_ldisc_open(struct tty_struct *tty)drivers/input/serio/serport.c 这个函数里面会创建一个serport结构体,并初始化

调用

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

drivers/tty/tty_io.c retval = ld->ops->ioctl(tty, file, cmd, arg);static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)设置

serport->id.proto = type & 0x000000ff;serport->id.id

=(type & 0x0000ff00)>> 8;serport->id.extra =(type & 0x00ff0000)>> 16;这里三个值一定要和serio总线驱动里面对应的值一致,serio总线就是靠它们来给设备和驱动建立联系的。

调用

read(fd, NULL, 0);跟踪代码到内核层tty_read:

static ssize_t tty_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)(ld->ops->read)(tty, file, buf, count)

这个ld就是tty当前的链路层结构,上面我们已经设置N_MOUSE为tty的当前链路层,因此ld->ops就是serport注册的serport_ldisc static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)

serio_register_port(serport->serio);

serio_init_port(serio);

serio_queue_event(serio, owner, SERIO_REGISTER_PORT);注册一个serio总线设备,关于serio总线,网络有很多资料介绍,这里就不说了。至此,我们的串口设备已经当做serio总线设备注册在serio总线上了,如果相应的驱动也在serio总线上,就会进行设备和驱动的匹配,然后调用驱动里面的connect函数,在这个函数里面就会创建input节点。我们的驱动和设备已经运行起来了,现在看看数据是如何传递的

先看具体串口中断函数: 我们以altera_uart.c为例: altera_uart_interrupt

altera_uart_rx_chars(pp)

tty_flip_buffer_push(port->state->port.tty);

flush_to_ldisc(&tty->buf.work);

disc->ops->receive_buf(tty, char_buf,flag_buf, count);disc->ops就是serport注册的serport_ldisc static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)

serio_interrupt(serport->serio, cp[i], ch_flags);

ret = serio->drv->interrupt(serio, data, dfl);drv->interrupt就是我们驱动函数提供一个函数,它每次接受一个字符,在这个函数里面,接受到足够信息后,就能得到触摸屏坐标信息,然后通过input_report上报上去。看看数据处理流程图:

总结:

要想让基于serio总线驱动的串口触摸屏能正常工作,在linux内核需要加载驱动模块,serport模块。还需要一个上层应用程序,这个程序需要进行以下工作

1、打开你要使用的串口,比如

open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)

device为/dev/ttyS0

2、设置串口波特率等,和你的串口触摸屏一致

3、给串口增加一个N_MOUSE链路层

4、设置你的串口触摸屏type,id,extra

5、读串口read(fd, NULL, 0);

下载基于多单片机的串口扩展设计论文[5篇材料]word格式文档
下载基于多单片机的串口扩展设计论文[5篇材料].doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    单片机课程论文设计-电子钟课程设计

    单片机课程论文设计 ——电子钟 一 课程设计的主要内容 1 设计思想 1.1硬件设计思想 1.1.1电路设计思想 电路原理图见图1,由动态数码显示组成时、分、秒的显示。把“单片机......

    51单片机论文

    课程设计报告 课程设计名称:智能控制避障小车 学生姓名: 班 级: 学 号: 成 绩: 指导教师: 开课时间:2016-2017学年第 一学期 I 独 创 声 明 本人声明所呈交的课程设计是本人在导......

    单片机课程设计论文

    目录题目:巡回检测报警控制系统第一章 实验任务及要求............1功能描述................2元件选择....... ................2第二章系统总体设计方案................3......

    基于单片机的时钟控制器设计论文

    单片机原理与应用技术课程设计报告 基于单片机控制的时钟控制器 专业班级: _电气XX班_ __ 姓名:__ ___XXX__ ___ 时 间:2013/11/25~12/15 指导教师: XXXX XXX 2013年12月11日......

    单片机设计心得

    四周的毕业设计结束了,在这次的毕业设计中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在设计过程中,与同学分工设计,和同学们......

    单片机导游应用论文

    文 章来源莲山 课件 w w w.5Y k J.Com 7 凌阳单片机在电子导游器中的应用是小柯论文网通过网络搜集,并由本站工作人员整理后发布的,凌阳单片机在电子导游器中的应用是篇质量较......

    素质扩展策划书(精选多篇)

    素 质 扩 展 策 划 书 一、 活动目的: 为了加强新老校区学生会的交流,增强学生会内部的凝聚力,培养队员们的团队意识和协作能力,创造集体和谐。 二、 活动主题: 沟通 友谊 团结......

    扩展型课文教学设计

    Unit 3 Travel journal I.Teaching aims and demands: 1.Skill goals: Describe a journey. Revise means of transportation. The Present Progressive Tense expresses f......