IO口模拟串口三种方法
单片机89C52的I_O模拟串口与PC机通信数据采集实现方法

第09卷 第11期 中 国 水 运 Vol.9 No.11 2009年 11月 China Water Transport November 2009收稿日期:2009-07-22作者简介:陈铭,湖北襄樊学院物理与电子工程学院自动化专业讲师。
单片机89C52的I/O 模拟串口与PC 机通信数据采集实现方法陈 铭(湖北襄樊学院 物理与电子工程学院,湖北 襄樊 441053)摘 要:在做电拉系统开发的过程中,为解决单片机89C52与PC 机通信问题,利用89C52的I/O 口模拟串口与PC 机进行通信,通过这种方法可以实现多个串1:7,而且串口通讯高效、可靠、标准统一 系统包括目标机采集子程序、目标机数据发送子程序、上位机接收子程序等,并给出了硬件原理图。
关键词:单片机89C52;模拟串1:7;数据采集;串1:7通讯中图分类号:TP274+.2 文献标识码:A 文章编号:1006-7973(2009)11-0109-02一、引 言电控技术是满足动力性、经济性的前提下有效降低排放的重要措施,在做电控EGR 系统的开发过程中,由于所用的PHYTEC 89C52开发板有一个串口被CrossView 调试器在调试时占用,所以这里用其I/0口来模拟串行口的功能与PC 机通信,把采集的数据和内部参数传给PC 机进行在线标定。
PC 与单片机构成的上位机、下位机分布式控制系统是一种常见的工业控制系统,单片机作为下位机可进行现场数据采集和就地控制,并可将采集到的数据或者状态信息传送到上位PC 机,以做进一步的分析处理。
在实际应用中,上位机与下位机的通信问题是首要解决的问题之一,串行通信以其高效率、可靠标准统一的优点成为重要的通信手段,本文即在Windows XP 环境下,使用C 语言实现89C52单片机(并口模拟串口)与PC 之间的串行通信,其通信线路通过RS 232连接(距离小于15 m)。
二、串行接口的基本通信方式串行接口的有异步和同步2种基本通信方式。
如何使用单片机的单个IO口模拟串口UART输出

IO_UART_TX_H(); } else {
IO_UART_TX_L(); asm("l.nop");//延时一个机器周期 } delay_one_bit_tx(); } IO_UART_TX_H();//发送结束位 delay_one_bit_tx(); }
1
V1.0
模拟的串口协议如下:
起始位 1 位 数据位 8 位 停止位 1 位 校验位 无
参考的代码如下:
void io_uart_send_byte(unsigned char dat) {
Unsigned char i ; IO_UART_TX_L();//拉低作为起始 delay_one_bit_tx();//按照需要的波特率来延时 for(i = 0 ; i< 8 ; i++) {
普通 MCU 模拟串口发送说明
相关说明:
(1)、模拟 115200 波特率,信号跳变的时间为 8.68uS = 1 / 115200 (2)、模拟 9600 波特率,信号跳变的时间为 104.1uS = 1 / 9600 (3)、串口的波特率越高,所需要的时间越短,相对稳定性越差,建议采用 9600 波特率。 (4)、串口的发射模拟相对比较容易,接收比较困难。下面就串口的 IO 模拟发射做说明 (5)、我们的串口允许的时钟误差最多 3%。所以用户请严格的控制时间误差在这个范围。
单片机I-O 口模拟串行通信设计

单片机I/O 口模拟串行通信设计关键字:单片机 IO口模拟串行通信目前普遍采用的MCS51 和PIC 系列单片机通常只有一个(或没有)UART异步串行通信接口,在应用系统中若需要多个串行接口(例如在多机通信系统中,主机既要和从机通信又要和终端通信)的情况下,通常的方法是扩展一片8251 或 8250 通用同步/异步接收发送芯片(USART),需额外占用单片机I/O 资源。
1.串行接口的基本通信方式串行接口的有异步和同步两种基本通信方式。
异步通信采用用异步传送格式,。
数据发送和接收均将起始位和停止位作为开始和结束的标志。
在异步通信中,起始位占用一位(低电平)。
异步通信采用用异步传送格式用来表示字符开始。
其后为7 或8 位的数据编码,第8 位通常做为奇偶校验位。
最后为停止位(高电平)用来表示字符传送结束。
上述字符格式通常作为一个串行帧,如无奇偶校验位,即为常见的N.8.1帧格式。
串行通信中,每秒传送的数据位称为波特率。
如数据传送的波特率为1200 波特,采用N.8.1 帧格式(10 位),则每秒传送字节为120 个,而字节中每一位传送时间即为波特率的倒数:T=I/1200=0.833ms。
同样,如数据传送的波特率为9600 波特,则字节中每一位传送时间为T=1/9600=0.104 ms。
2.硬件电路89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低电压、高性能CMOS8位微处理器,俗称单片机。
单片机的可擦除只读存储器可以反复擦除100次。
该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。
由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的89C51是一种高效微控制器,89C2051是它的一种精简版本。
51单片机IO口模拟串口

论坛新老朋友们。
祝大家新年快乐。
在新的一年开始的时候,给大家一点小小的玩意。
工程师经常碰到需要多个串口通信的时候,而低端单片机大多只有一个串行口,甚至没有串口。
这时候无论是选择高端芯片,还是更改系统设计都是比较麻烦的事。
我把以前搞的用普通I/O口模拟串行口通讯的程序拿出来,供大家参考,希望各位兄弟轻点拍砖。
基本原理:我们模拟的是串行口方式1.就是最普通的方式。
一个起始位、8个数据位、一个停止位。
模拟串行口最关键的就是要计算出每个位的时间。
以波特率9600为例,每秒发9600个位,每个位就是1/9600秒,约104个微秒。
我们需要做一个精确的延时,延时时间+对IO口置位的时间=104微秒。
起始位是低状态,再延时一个位的时间。
停止位是高状态,也是一个位的时间。
数据位是8个位,发送时低位先发出去,接收时先接低位。
了解这些以后,做个IO 模拟串口的程序,就是很容易的事。
我们开始。
先上简单原理图:就一个MAX232芯片,没什么好说的,一看就明白。
使用单片机普通I/O口,232数据输入端使用51单片机P3.2口(外部中断1口,接到普通口上也可以,模拟中断方式的串行口会有用。
呵呵)。
数据输出为P0.4(随便哪个口都行)。
下面这个程序,您只需吧P0.4 和P3.2 当成串口直接使用即可,经过测试完全没有问题. 2、底层函数代码如下:sbit TXD1 = P0^4; //定义模拟输出脚sbit RXD1 = P3^2; //定义模拟输入脚bdata unsigned char SBUF1; //定义一个位操作变量sbit SBUF1_bit0 = SBUF1^0;sbit SBUF1_bit1 = SBUF1^1;sbit SBUF1_bit2 = SBUF1^2;sbit SBUF1_bit3 = SBUF1^3;sbit SBUF1_bit4 = SBUF1^4;sbit SBUF1_bit5 = SBUF1^5;sbit SBUF1_bit6 = SBUF1^6;sbit SBUF1_bit7 = SBUF1^7;void delay_bps() {unsigned char i; for (i = 0; i < 29; i++); _nop_();_nop_();} //波特率9600 模拟一个9600波特率unsigned char getchar2() //模拟接收一个字节数据{while (RXD1);_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();delay_bps();SBUF1_bit0 = RXD1; //0delay_bps();SBUF1_bit1 = RXD1; //1delay_bps();SBUF1_bit2 = RXD1; //2delay_bps();SBUF1_bit3 = RXD1; //3delay_bps();SBUF1_bit4 = RXD1; //4delay_bps();SBUF1_bit5 = RXD1; //5delay_bps();SBUF1_bit6 = RXD1; //6delay_bps();SBUF1_bit7 = RXD1; //7delay_bps();return(SBUF1) ; //返回读取的数据}void putchar2(unsigned char input) //模拟发送一个字节数据{SBUF1 = input;TXD1 = 0; //起始位delay_bps();TXD1 = SBUF1_bit0; //0delay_bps();TXD1 = SBUF1_bit1; //1delay_bps();TXD1 = SBUF1_bit2; //2delay_bps();TXD1 = SBUF1_bit3; //3delay_bps();TXD1 = SBUF1_bit4; //4delay_bps();TXD1 = SBUF1_bit5; //5delay_bps();TXD1 = SBUF1_bit6; //6delay_bps();TXD1 = SBUF1_bit7; //7delay_bps();TXD1 = 1; //停止位delay_bps();}3、实现串行通讯。
模拟串口的实现单片机IO口

TR0=1;
TF0=0;
}
void WByte(uchar input)//send function
{
uchar i=8;
TR0=1;
TXD1=0;//begin bit
WaitTF0();
//send the Byte
while(i--)
{
TXD1=input&0x01;//send Byte from low bit to highbit
模拟串口的实现单片机IO口
用EBOX向我们的电力线调试模块发数据,但是要有一个控制接口,但是
EBOX没有提供,所有只好用MCU来做伺服器。一般的单片机都只有一个串
口,所以必须模拟一个出来。
/*
sbit TXD1=P1;//definep14 as theanalogtransmit port
sbit RXD1= P1 ;//definep12 as theanalog recieve port
i=i;
i=i;
i=i;
i=i;
i=i;
i=i;
i=i;
TR0=1;//计数器开始工作
WaitTF0();
while(i--)//接收8位数据位
{
Output>>=1;
if(RXD1)Output=Output|0x80;//recieve from the highbit tolow bit
WaitTF0();
WaitTF0();
input=input>>1;//rightshift
}
TXD1=1;//stop bit
WaitTF0();
TR0=0;//stop thecounter
基于单片机I/O口模拟的SPI串行通信实现

基于单片机I/O口模拟的SPI串行通信实现【摘要】基于单片机或ARM芯片的普通I/O口,模拟实现SPI串行通信。
模拟SPI通信需严格时钟时序,只有当主器件模拟的SPI时序与从器件的SPI时序完全一致时,才能实现SPI通信的正常数据交换。
【关键词】I/O口;SPI时序;主器件;从器件1.引言SPI(SeIial Peripheral Interfa即串行外围设备接口)总线技术是一种高效率的串行接口技术,主要用于扩展外设和进行数据交换。
在许多单片机中,已经作为一种标准配置。
但某些应用非常广泛的单片机并不带标准SPI接口,这样就限制了在这些系统中使用带SPI接口的器件。
解决该问题的方法是使用单片机的普通I/O口通过软件模拟的方式实现SPI串口通信,以满足应用需求。
此外,采用标准的SPI接口有很多局限性,在设备外围开发和扩展增加负担,而通过I/O口模拟实现SPI通信将不受这些限制,可轻松实现其外围开发和扩展,灵活性更大;通过I/O口模拟SPI通信,其通用性和可移植性强,实现简单、方便。
2.SPI总线概述SPI通信的总线形式一般采用4线制,即为使能控制线SN、始终控制线SCLK、主出从入线MOSI和主入从出线MISO。
可实现一个主控制器挂接多个从控制器,如图1所示,为SPI总线框图。
使能控制线SN完成对从控制器的片选,当需要与某个控制通信时,将SN 置于打开(高或者低,根据不同芯片分别对待)状态,使从控制器处于可通信状态,同时时钟控制线SCLK用于控制SPI通信的时序,该时序需与从控制器的SPI时序保持完全一致,这样才能保证SPI通信的实现。
主出从入线MOSI为SPI 串口通信数据输出线,主入从出线MISO为SPI串口通信数据输入线。
当主控制器MCU只与一个从控制器通信或所选从控制器无使能控制端时,使能控制线SN可不用,即3线制SPI通信,也可实现模拟SPI通信。
3.SPI通信时序控制相对于标准的SPI通信接口,通过I/O口模拟的SPI通信,其模拟时序要求很严格,即主控制器模拟的SPI时序必须与从控制器的SPI通信时序保持一致,否则会导致在通信时出现接收不到数据或是接收数据错误的情况。
模拟串口的三种方法及C语言

模拟串口的三种方法及C语言模拟串口是软件中模拟实现串口通信的一种方法,它是在电脑上通过软件模拟两个串口之间的传输,用来测试、调试串口相关的应用程序。
本文将介绍三种常见的模拟串口的方法,并提供C语言代码示例。
1.使用虚拟串口软件虚拟串口软件是一种用于模拟串口通信的应用程序。
它创建了虚拟的串口设备,使其在电脑上模拟出真实的串口通信环境。
通过虚拟串口软件,可以实现串口的模拟收发数据,可以连接到串口测试工具、串口调试工具或者自己编写的串口通信程序上。
以下是一个使用虚拟串口软件模拟串口通信的C语言代码示例:```c#include <stdio.h>#include <windows.h>int mai//打开虚拟串口//检测串口是否成功打开printf("Error in opening serial port\n");return 1;}//进行串口通信操作,如发送、接收数据//关闭串口return 0;```在这个示例中,我们使用了Windows操作系统的函数`CreateFile`来打开一个虚拟串口,这里的串口名称是"COM1"。
然后可以调用相关函数进行串口通信操作,最后用`CloseHandle`函数关闭串口。
2.使用串口驱动模拟在一些情况下,可以通过修改电脑的串口驱动程序来模拟串口通信。
这种方法需要更深入的了解操作系统的底层机制,并进行驱动程序的开发和修改。
通过修改串口驱动程序,可以模拟出一个虚拟的串口设备,通过这个设备进行串口通信。
以下是一个简单的C语言代码示例,用于修改串口驱动程序来模拟串口通信:```c#include <stdio.h>#include <fcntl.h>#include <unistd.h>int maiint fd;//打开串口设备fd = open("/dev/ttyS0", O_RDWR);//检测串口是否成功打开if (fd < 0)printf("Error in opening serial port\n");return 1;}//进行串口通信操作,如发送、接收数据//关闭串口设备close(fd);return 0;```在这个示例中,我们使用了Linux操作系统的函数`open`来打开一个串口设备,这里的设备名称是"/dev/ttyS0"。
51单片机模拟串口的三种方法

51单片机模拟串口的三种方法51单片机模拟串口的三种方法随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。
这种情况下下,采集会需要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的51系列只提供一个串口,那么另一个串口只能靠程序模拟。
本文所说的模拟串口,就是利用51的两个输入输出引脚如P1.0和P1.1,置1或0分别代表高低电平,也就是串口通信中所说的位,如起始位用低电平,则将其置0,停止位为高电平,则将其置1,各种数据位和校验位则根据情况置1或置0。
至于串口通信的波特率,说到底只是每位电平持续的时间,波特率越高,持续的时间越短。
如波特率为9600BPS,即每一位传送时间为1000ms/9600=0.104ms,即位与位之间的延时为为0.104毫秒。
单片机的延时是通过执行若干条指令来达到目的的,因为每条指令为1-3个指令周期,可即是通过若干个指令周期来进行延时的,单片机常用11.0592M的的晶振,现在我要告诉你这个奇怪数字的来历。
用此频率则每个指令周期的时间为(12/11.0592)us,那么波特率为9600BPS每位要间融多少个指令周期呢?指令周期s=(1000000/9600)/(12/11.0592)=96,刚好为一整数,如果为4800BP S则为96x2=192,如为19200BPS则为48,别的波特率就不算了,都刚好为整数个指令周期,妙吧。
至于别的晶振频率大家自已去算吧。
现在就以11.0592M的晶振为例,谈谈三种模拟串口的方法。
方法一:延时法通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期。
#define uchar unsigned charsbit P1_0 = 0x90;sbit P1_1 = 0x91;sbit P1_2 = 0x92;#define RXD P1_0#define TXD P1_1#define WRDYN 44 //写延时#define RDDYN 43 //读延时//往串口写一个字节void WByte(uchar input){uchar i=8;TXD=(bit)0; //发送启始位Delay2cp(39);//发送8位数据位while(i--){TXD=(bit)(input&0x01); //先传低位Delay2cp(36);input=input>>1;}//发送校验位(无)TXD=(bit)1; //发送结束位Delay2cp(46);}//从串口读一个字节uchar RByte(void){uchar Output=0;uchar i=8;uchar temp=RDDYN;//发送8位数据位Delay2cp(RDDYN*1.5); //此处注意,等过起始位 while(i--){Output >>=1;if(RXD) Output |=0x80; //先收低位Delay2cp(35); //(96-26)/2,循环共占用26个指令周期}while(--temp) //在指定的时间内搜寻结束位。
模拟串口

/****************************************************作者:温子祺*联系方式:wenziqi@*说明:模拟串口实验***************************************************/传统的8051系列单片机一般都配备一个串口,而STC89C52RC增强型单片机也不例外,只有一个串口可供使用,这样就出问题了,假如当前单片机系统要求二个串口或多个串口进行同时通信,8051系列单片机只有一个串口可供通信就显得十分尴尬,但是在实际的应用中,有两种方法可以选择。
方法1:使用能够支持多串口通信的单片机,不过通过更换其他单片机来代替8051系列单片机,这样就会直接导致成本的增加,优点就是编程简单,而且通信稳定可靠。
方法2:在IO资源比较充足的情况下,可以通过IO来模拟串口的通信,虽然这样会增加编程的难度,模拟串口的波特率会比真正的串口通信低一个层次,但是唯一优点就是成本上得到控制,而且通过不同的IO 组合可以实现更加之多的模拟串口,在实际应用中往往会采用模拟串口的方法来实现多串口通信。
普遍使用串口通信的数据流都是1位起始位、8位数据位、1位停止位的格式的,如表1。
表1要注意的是,起始位作为识别是否有数据到来,停止位标志数据已经发送完毕。
起始位固定值为0,停止位固定值为1,那么为什么起始位要是0,停止位要是1呢?这个很好理解,假设停止位固定值为1,为了更加易识别数据的到来,电平的跳变最为简单也最容易识别,那么当有数据来的时候,只要在规定的时间内检测到发送过来的第一位的电平是否0值,就可以确定是否有数据到来;另外停止位为1的作用就是当没有收发数据之后引脚置为高电平起到抗干扰的作用。
在平时使用红外无线收发数据时,一般都采用模拟串口来实现的,但是有个问题要注意,波特率越高,传输距离越近;波特率越低,传输距离越远。
对于这些通过模拟串口进行数据传输,波特率适宜为1200b/s 来进行数据传输。
单片机IO口模拟串口程序(发送+接收)

单片机IO口模拟串口程序(发送+接收)前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口。
经过若干曲折并参考了一些现有的资料,基本上完成了。
现在将完整的测试程序,以及其中一些需要总结的部分贴出来。
程序硬件平台:11.0592M晶振,STC单片机(兼容51)/************************************** ************************** 在单片机上模拟了一个串口,使用P2.1作为发送端* 把单片机中存放的数据通过P2.1作为串口TXD发送出去*************************************** ************************/#include <reg51.h>#include <stdio.h>#include <string.h>typedef unsigned char uchar;int i;uchar code info[] ={0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x5 5,0x55,0x55,0x55,0x55,0x55,0x55,0x55 };sbit newTXD = P2^1;//模拟串口的发送端设为P2.1void UartInit(){SCON = 0x50; // SCON: serail mode 1, 8-bit UARTTMOD |= 0x21; // T0工作在方式1,十六位定时PCON |= 0x80; // SMOD=1;TH0 = 0xFE; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=11.0592MHzTL0 = 0x7F; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=11.0592MHz// TH0 = 0xFD; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=18.432MHz// TL0 = 0x7F; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=18.432MHz}void WaitTF0(void){while(!TF0);TF0=0;TH0=0xFE; // 定时器重装初值fosc=11.0592MHzTL0=0x7F; // 定时器重装初值fosc=11.0592MHz// TH0 = 0xFD; // 定时器重装初值 fosc=18.432MHz// TL0 = 0x7F; // 定时器重装初值 fosc=18.432MHz}void WByte(uchar input){//发送启始位uchar j=8;TR0=1;newTXD=(bit)0;WaitTF0();//发送8位数据位while(j--){newTXD=(bit)(input&0x01); //先传低位WaitTF0();input=input>>1;}//发送校验位(无)//发送结束位newTXD=(bit)1;WaitTF0();TR0=0;}void Sendata(){for(i=0;i<sizeof(info);i++)//外层循环,遍历数组{WByte(info[i]);}}void main(){UartInit();while(1){Sendata();}}########################################## ####################################/************************************** ************************** 模拟接收程序,这个程序的作用从模拟串口接收数据,然后将这些数据发送到实际串口* 在单片机上模拟了一个串口,使用P3.2作为发送和接收端* 以P3.2模拟串口接收端,从模拟串口接收数据发至串口*************************************** ************************/#include<reg51.h>#include<stdio.h>#include<string.h>typedef unsigned char uchar ;//这里用来切换晶振频率,支持11.0592MHz 和18.432MHz//#define F18_432#define F11_0592uchar tmpbuf2[64]={0};//用来作为模拟串口接收数据的缓存struct{uchar recv :6 ;//tmpbuf2数组下标,用来将模拟串口接收到的数据存放到tmpbuf2中uchar send :6 ;//tmpbuf2数组下标,用来将tmpbuf2中的数据发送到串口}tmpbuf2_point={0,0};sbit newRXD=P3^2 ;//模拟串口的接收端设为P3.2void UartInit(){SCON=0x50 ;// SCON: serail mode 1, 8-bit UARTTMOD|=0x21 ;// TMOD: timer 1, mode 2, 8-bit reload,自动装载预置数(自动将TH1送到TL1);T0工作在方式1,十六位定时PCON|=0x80 ;// SMOD=1;#ifdef F11_0592TH1=0xE8 ;// Baud:2400 fosc=11.0592MHz 2400bps为从串口接收数据的速率TL1=0xE8 ;// 计数器初始值,fosc=11.0592MHz 因为TH1一直往TL1送,所以这个初值的意义不大TH0=0xFF ;// 定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bps fosc=11.0592MHzTL0=0xA0 ;// 定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bps fosc=11.0592MHz#endif#ifdef F18_432TH1=0xD8 ;// Baud:2400fosc=18.432MHz 2400bps为从串口接收数据的速率TL1=0xD8 ;// 计数器初始值,fosc=18.432MHz 因为TH1一直往TL1送,所以这个初值的意义不大TH0=0xFF ;// 定时器0初始值,延时104us,目的是令模拟串口的波特率为9600bps fosc=18.432MHzTL0=0x60 ;// 定时器0初始值,延时104us,目的是令模拟串口的波特率为9600bps fosc=18.432MHz#endifIE|=0x81 ;// 中断允许总控制位EA=1;使能外部中断0TF0=0 ;IT0=1 ;// 设置外部中断0为边沿触发方式TR1=1 ;// 启动TIMER1,用于产生波特率}void WaitTF0(void){while(!TF0);TF0=0 ;#ifdef F11_0592TH0=0xFF ;// 定时器重装初值模拟串口的波特率为9600bps fosc=11.0592MHz TL0=0xA0 ;// 定时器重装初值模拟串口的波特率为9600bps fosc=11.0592MHz #endif#ifdef F18_432TH0=0xFF ;// 定时器重装初值 fosc=18.432MHzTL0=0x60 ;// 定时器重装初值 fosc=18.432MHz#endif}//接收一个字符uchar RByte(){uchar Output=0 ;uchar i=8 ;TR0=1 ;//启动Timer0#ifdef F11_0592TH0=0xFF ;// 定时器重装初值模拟串口的波特率为9600bps fosc=11.0592MHz TL0=0xA0 ;// 定时器重装初值模拟串口的波特率为9600bps fosc=11.0592MHz #endif#ifdef F18_432TH0=0xFF ;// 定时器重装初值fosc=18.432MHzTL0=0x60 ;// 定时器重装初值fosc=18.432MHz#endifTF0=0 ;WaitTF0();//等过起始位//接收8位数据位while(i--){Output>>=1 ;if(newRXD)Output|=0x80 ;//先收低位WaitTF0();//位间延时}TR0=0 ;//停止Timer0return Output ;}//向COM1发送一个字符void SendChar(uchar byteToSend){SBUF=byteToSend ;while(!TI);TI=0 ;}void main(){UartInit();while(1){if(tmpbuf2_point.recv!=tmpbuf2_point.send)//差值表示模拟串口接收数据缓存中还有多少个字节的数据未被处理(发送至串口){SendChar(tmpbuf2[tmpbuf2_point.send++]);}}}//外部中断0,说明模拟串口的起始位到来了void Simulated_Serial_Start()interrupt 0{EX0=0 ;//屏蔽外部中断0tmpbuf2[tmpbuf2_point.recv++]=RByte(); //从模拟串口读取数据,存放到tmpbuf2数组中IE0=0 ;//防止外部中断响应2次,防止外部中断函数执行2次EX0=1 ;//打开外部中断0}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~以上是两个独立的测试程序,分别是模拟串口发送的测试程序和接收的测试程序上面两个程序在编写过程中参考了这篇文章《51单片机模拟串口的三种方法》(在后文中简称《51》),但在它的基础上做了一些补充,下面是若干总结的内容:1、《51》在接收数据的程序中,采用的是循环等待的方法来检测起始位(见《51》的“附:51 IO 口模拟串口通讯C源程序(定时器计数法)”部分),这种方法在较大程序中,可能会错过起始位(比如起始位到来的时候程序正好在干别的,而没有处于判断起始位到来的状态),或者一直在检测起始位,而没有办法完成其他工作。
单片机IO口模拟SPI四种模式的程序

单片机IO口模拟SPI四种模式的程序单片机IO口模拟SPI四种模式的程序#include "iom8535v.h"#define _CPOL 1#define _CPHA 0#define SCK_IO DDRA|=0X01#define MOSI_IO DDRA|=0X02#define MISO_IO DDRA&=0XFB#define SSEL_IO DDRA|=0X08#define SCK_D(X) (X?(PORTA|=0X01):(PORTA&=0XFE)) #define MOSI_D(X) (X?(PORTA|=0X02):(PORTA&=0XFD)) #define SSEL_D(X) (X?(PORTA|=0X08):(PORTA&=0XF7))#define MISO_I() (PINA&0X04)void delay(){unsigned char m,n;for(n=0;n<5;n++);for(m=0;m<100;m++);}/************************************************ 端口方向配置与输出初始化************************************************/ void SPI_Init(void){SCK_IO ;MOSI_IO ;MISO_IO ;SSEL_IO ;SSEL_D(1);MOSI_D(1);#if _CPOL==0SCK_D(0);#elseSCK_D(1);#endif}/**********************************************模式零写数据***********************************************/ #if _CPOL==0&&_CPHA==0 //MODE 0 0 void SPI_Send_Dat(unsigned char dat){unsigned char n;for(n=0;n<8;n++){SCK_D(0);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(1);}SCK_D(0);}/********************************************* 模式零读数据*********************************************/ unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;for(n=0;n<8;n++)SCK_D(0);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(1);}SCK_D(0);return dat;}#endif/********************************************** 模式二写数据***********************************************/ #if _CPOL==1&&_CPHA==0 //MODE 1 0 void SPI_Send_Dat(unsigned char dat){unsigned char n;for(n=0;n<8;n++){SCK_D(1);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(0);}SCK_D(1);}/********************************************* 模式二读数据*********************************************/ unsigned char SPI_Receiver_Dat(void)unsigned char n ,dat,bit_t;for(n=0;n<8;n++){SCK_D(1);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(0);}SCK_D(1);return dat;}#endif/********************************************* 模式一写数据*********************************************/ #if _CPOL==0&&_CPHA==1 //MODE 0 1 void SPI_Send_Dat(unsigned char dat){unsigned char n;SCK_D(0);for(n=0;n<8;n++){SCK_D(1);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(0);}}/********************************************* 模式一读数据*********************************************/ unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;for(n=0;n<8;n++){SCK_D(1);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(0);}SCK_D(0);return dat;}#endif//////////////////////////////////////////////////////////////////////////////////////////////////////////////#if _CPOL==1&&_CPHA==1 //MODE 1 1void SPI_Send_Dat(unsigned char dat){unsigned char n;SCK_D(1);for(n=0;n<8;n++){SCK_D(0);if(dat&0x80)MOSI_D(1);else MOSI_D(0);dat<<=1;SCK_D(1);}}/************************************模式三读数据************************************/unsigned char SPI_Receiver_Dat(void){unsigned char n ,dat,bit_t;SCK_D(0);for(n=0;n<8;n++){ SCK_D(0);dat<<=1;if(MISO_I())dat|=0x01;else dat&=0xfe;SCK_D(1);}SCK_D(1);return dat;}#endif/**************************************************************************/ void main() {SPI_Init();DDRB = 0XFF;//#if _CPOL//SCK_D(0);//#endifwhile(1){//SSEL_D(0);//SPI_Send_Dat(0x01);//SPI_Send_Dat(0x31);//SSEL_D(1);SSEL_D(0);SPI_Send_Dat(0x81); PORTB =SPI_Receiver_Dat(); SSEL_D(1);//delay();}}。
并行IO口模拟串行I2C总线技术.

第14卷第1期西南工学院学报V o l . 14N o . 11999年3月JOU RNAL O F SOU THW EST I N ST ITU T E O F T ECHNOLO GY M ar . 1999 并行I O 口模拟串行I 2C 总线技术马建国刘桂华a (信息与控制工程系绵阳621002摘要单片机I O 口资源馈乏是当前微机控制系统中的一个十分重要的问题, 通常采用硬件电路去扩展I O 口, 但使线路复杂, 且影响了微控系统的整体性能。
I 2C 总线是解决I O 口资源馈乏的有效途径。
而目前大多数单片机自身并不带I 2C 接口。
本文介绍了用单片机两个普通I O 模拟I 2C 总线技术, 针对一典型应用实例, 用单片机普通I O 口模拟I 2C 总线和多个串行存储器件E 2PROM 进行数据通讯, 并给出了硬件设计电路及对多个存储器件E 2PROM 进行存数和读数的程序设计。
关键词:I 2C 总线单片机I O 接口并行接口串行接口中图法分类号:T P 2140引言在目前单片机控制系统中, 显示、数据、程序存储、数字量和模拟量输入输出以及通讯, 均需占用I O 口。
如对于一个拥有4位L ED 显示器件, 一个数据存储器件, 一个微打, 4×4键盘, 4位I O 口的简单的微控系统, 通常需要48根线以上I O 资源。
而一般的单片机, 除去一些中断, 复位, 定时器I O 口占用部分复用I O 外, 远不能满足需要, 通常用8155、8255、373、245去扩展I O 口, 而硬件扩展I O 口使系统线路复杂, 印制板面积增大, 成本增高, 且整体性能降低。
PH I L IP 公司推出I 2C 总线专利技术是解决资源紧张的有效措施。
I 2C总线是目前最完善的外围器件的扩展总线, 具有最完善的总线规范和最方便用户界面, 其上可挂接多达128个串行外围器件或设备。
用单片机普通I O 口可模拟I 2C 总线, 实现与外围器件或设备的通讯, 只需占两个I O 口, 在硬件连接上省去片选线。
模拟串口的三种方法及C语言

51单片机模拟串口的三种方法[ 2007-8-2 9:50:00 | By: MCUBLOG ](转)随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。
这种情况下下,采集会需要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的51系列只提供一个串口,那么另一个串口只能靠程序模拟。
本文所说的模拟串口,就是利用51的两个输入输出引脚如P1.0和P1.1,置1或0分别代表高低电平,也就是串口通信中所说的位,如起始位用低电平,则将其置0,停止位为高电平,则将其置1,各种数据位和校验位则根据情况置1或置0。
至于串口通信的波特率,说到底只是每位电平持续的时间,波特率越高,持续的时间越短。
如波特率为9600BPS,即每一位传送时间为1000ms/9600=0.104ms,即位与位之间的延时为为0.104毫秒。
单片机的延时是通过执行若干条指令来达到目的的,因为每条指令为1-3个指令周期,可即是通过若干个指令周期来进行延时的,单片机常用11.0592M的的晶振,现在我要告诉你这个奇怪数字的来历。
用此频率则每个指令周期的时间为(12/11.0592)us,那么波特率为9600BPS每位要间融多少个指令周期呢?指令周期s=(1000000/9600)/(12/11.0592)=96,刚好为一整数,如果为4800BPS则为96x2=192,如为19200BPS则为48,别的波特率就不算了,都刚好为整数个指令周期,妙吧。
至于别的晶振频率大家自已去算吧。
现在就以11.0592M的晶振为例,谈谈三种模拟串口的方法。
方法一:延时法通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期。
#define uchar unsigned charsbit P1_0 = 0x90;sbit P1_1 = 0x91;sbit P1_2 = 0x92;#define RXD P1_0#define TXD P1_1#define WRDYN 44 //写延时#define RDDYN 43 //读延时//往串口写一个字节void WByte(uchar input){uchar i=8;TXD=(bit)0; //发送启始位Delay2cp(39);//发送8位数据位while(i--){TXD=(bit)(input&0x01); //先传低位Delay2cp(36);input=input>>1;}//发送校验位(无)TXD=(bit)1; //发送结束位Delay2cp(46);}//从串口读一个字节uchar RByte(void){uchar Output=0;uchar i=8;uchar temp=RDDYN;//发送8位数据位Delay2cp(RDDYN*1.5); //此处注意,等过起始位while(i--){Output >>=1;if(RXD) Output |=0x80; //先收低位Delay2cp(35); //(96-26)/2,循环共占用26个指令周期}while(--temp) //在指定的时间内搜寻结束位。
单片机IO口模拟串行实现数据通信

目录1设计任务与要求 (1)2总体方案设计 (1)2.1串行通信的方式设计 (1)2.1.1并行I/O口 (1)2.1.2通信的基本原理 (2)2.1.3 89C51的串行口 (5)2.1.4 用IO口模拟串口通信 (7)2.2 数码管显示设计 (7)2.3 LED灯显示设计 (8)3单元电路设计 (8)3.1硬件设计 (8)3.1.1复位电路设计 (10)3.1.2时钟电路 (10)3.1.3 显示电路设计 (11)3.1.4电平转换电路 (12)3.2软件设计 (14)3.2.1 程序设计流程图 (14)3.2.2 单片机IO口模拟串口实现数据通信的源程序 (15)4系统仿真 (18)5收获与体会 (20)6参考文献 (21)单片机IO口模拟串口实现数据通信1设计任务与要求本设计为单片机IO口模拟串口实现数据通信,它可以用单片机的IO口实现单片机RX和TX的功能。
具体要求如下:●用单片机的P3.4和P3.5分别模拟RX和TX的串行通信功能,能够接收和发送数据。
●通过PC机的键盘输入字符,并传送给单片机,由单片机接收后,发达给PC机,由PC机加以显示。
●单片机接收由键盘输入的数据后,如果是数字,则由数码管显示,并由LED灯表示其ASCII码,如果是其他字符,则由仅由LED灯显示其ASCII码。
2总体方案设计2.1串行通信的方式设计本设计要求用单片机的IO口来模拟串口的串行通信,因此有必要先简要介绍一下单片机的IO和通信的基本原理与串行口P3.0和P3.1。
2.1.1并行I/O口MCS-51单片机共有4个双向的8位并行I/O端口(Port),分别记作P0-P3,共有32根口线,各口的每一位均由锁存器、输出驱动器和输入缓冲器所组成。
实际上P0-P3已被归入特殊功能寄存器之列。
这四个口除了按字节寻址以外,还可以按位寻址。
由于它们在结构上有一些差异,故各口的性质和功能有一些差异。
P0口是双向8位三态I/O口,此口为地址总线(低8位)及数据总线分时复用口,可驱动8个LS型TTL负载。
51单片机模拟串口通讯

论坛新老朋友们。
祝大家新年快乐。
在新的一年开始的时候,给大家一点小小的玩意。
工程师经常碰到需要多个串口通信的时候,而低端单片机大多只有一个串行口,甚至没有串口。
这时候无论是选择高端芯片,还是更改系统设计都是比较麻烦的事。
我把以前搞的用普通I/O口模拟串行口通讯的程序拿出来,供大家参考,希望各位兄弟轻点拍砖。
基本原理:我们模拟的是串行口方式1.就是最普通的方式。
一个起始位、8个数据位、一个停止位。
模拟串行口最关键的就是要计算出每个位的时间。
以波特率9600为例,每秒发9600个位,每个位就是1/9600秒,约104个微秒。
我们需要做一个精确的延时,延时时间+对IO口置位的时间=104微秒。
起始位是低状态,再延时一个位的时间。
停止位是高状态,也是一个位的时间。
数据位是8个位,发送时低位先发出去,接收时先接低位。
了解这些以后,做个IO模拟串口的程序,就是很容易的事。
我们开始。
先上简单原理图:就一个MAX232芯片,没什么好说的,一看就明白。
使用单片机普通I /O口,232数据输入端使用51单片机P3.2口(外部中断1口,接到普通口上也可以,模拟中断方式的串行口会有用。
呵呵)。
数据输出为P0.4(随便哪个口都行)。
下面这个程序,您只需吧P0.4 和P3.2 当成串口直接使用即可,经过测试完全没有问题.2、底层函数代码如下:sbit TXD1 = P0^4; //定义模拟输出脚sbit RXD1 = P3^2; //定义模拟输入脚bdata unsigned char SBUF1; //定义一个位操作变量sbit SBUF1_bit0 = SBUF1^0;sbit SBUF1_bit1 = SBUF1^1;sbit SBUF1_bit2 = SBUF1^2;sbit SBUF1_bit3 = SBUF1^3;sbit SBUF1_bit4 = SBUF1^4;sbit SBUF1_bit5 = SBUF1^5;sbit SBUF1_bit6 = SBUF1^6;sbit SBUF1_bit7 = SBUF1^7;void delay_bps() {unsigned char i; for (i = 0; i < 29; i++); _nop_(); _nop_();} //波特率9600 模拟一个9600波特率unsigned char getchar2() //模拟接收一个字节数据{while (RXD1);_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); delay_bps();SBUF1_bit0 = RXD1; //0delay_bps();SBUF1_bit1 = RXD1; //1delay_bps();SBUF1_bit2 = RXD1; //2delay_bps();SBUF1_bit3 = RXD1; //3delay_bps();SBUF1_bit4 = RXD1; //4delay_bps();SBUF1_bit5 = RXD1; //5delay_bps();SBUF1_bit6 = RXD1; //6delay_bps();SBUF1_bit7 = RXD1; //7delay_bps();return(SBUF1) ; //返回读取的数据}void putchar2(unsigned char input) //模拟发送一个字节数据{SBUF1 = input;TXD1 = 0; //起始位delay_bps();TXD1 = SBUF1_bit0; //0delay_bps();TXD1 = SBUF1_bit1; //1delay_bps();TXD1 = SBUF1_bit2; //2delay_bps();TXD1 = SBUF1_bit3; //3delay_bps();TXD1 = SBUF1_bit4; //4delay_bps();TXD1 = SBUF1_bit5; //5delay_bps();TXD1 = SBUF1_bit6; //6delay_bps();TXD1 = SBUF1_bit7; //7delay_bps();TXD1 = 1; //停止位delay_bps();}3、实现串行通讯。
普通IO模拟串口收发程序

缓冲区满后,将缓冲区中的内容原样发回。这是为了测试多字节连续收发的能力和 简化程序。实际应用中应防止缓冲区溢出。 6. 由接收转换到发送时要先调用 soft_send_enable (); 由发送转换到接收时要先调用 soft_receive_enable ()。 7. 发送最后一个字节后如果要立刻转为接收,必须等待最后一个字节后发送完毕
void soft_send_enable (void) {
TCON_ENABLE_TIMER = 0; rs_f_TI_enable = 1; rs_f_RI_enable = 0;
//允许发送
//停止定时器 //允许发送 //禁止接收
rs_shift_count = 0; rs_f_TI = 1; TCON_ENABLE_TIMER = 1; }
//允许定时器中断 //监测起始位
//停止定时器
//启动定时器
void soft_receive_enable() {
rs_f_RI_enable = 1; rs_f_TI_enable = 0; soft_receive_init(); }
//允许接收
//允许接收 //禁止发送 //监测起始位, RXD 下降沿触发接收字节过程.
#define TMOD_COUNT_MODE 0x50;
//设置计数模式位
sbit TCON_ENABLE_TIMER = TCON^6; //
IO口模拟UART串口通信

IO口模拟UART串口通信为了让大家充分理解UART串口通信的原理,我们先用P3.0和P3.1这两个当做IO口来开展模拟实际串口通信的过程,原理搞懂后,我们再使用存放器配置实现串口通信过程。
对于UART串口波特率,常用的值是300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200、128000、256000等速率。
IO口模拟UART串行通信程序是一个简单的演示程序,我们使用串口调试助手下发一个数据,数据加1后,再自动返回。
串口调试助手,在我们开展全板子测试视频的时候,大家已经见过,这里我们直接使用STC-ISP软件自带的串口调试助手,先把串口调试助手使用给大家说一下,如图1所示。
第一步要选择串口助手菜单,第二步选择十六进制显示,第三步选择十六进制发送,第四步选择COM口,这个COM口要和自己电脑设备管理器里的那个COM口一致,波特率是我们程序设定好的选择,我们程序中让一个数据位持续时间是1/9600秒,那这个地方选择波特率就是选9600,校验位选N,数据位8,结束位1。
图1串口调试助手示意图串口调试助手的实质就是我们利用电脑上的UART通信接口,通过这个UART接口发送数据给我们的单片机,也可以把我们的单片机发送的数据接收到这个调试助手界面上。
因为初次接触通信方面的技术,所以我对这个程序开展一下解释,大家可以边看我的解释边看程序,把底层原理先彻底弄懂。
变量定义部分就不用说了,直接看main主函数。
首先是对通信的波特率的设定,在这里我们配置的波特率是9600,那么串口调试助手也得是9600。
配置波特率的时候,我们用的是定时器0的模式2。
模式2中,不再是TH0代表高8位,TL0代表低8位了,而只有TL0在开展计数了。
当TL0溢出后,不仅仅会让TF0变1,而且还会将TH0中的内容重新自动装到TL0中。
这样有一个好处,我们可以把我们想要的定时器初值提前存在TH0中,当TL0溢出后,TH0自动把初值就重新送入TL0了,全自动的,不需要程序上再给TL0重新赋值了,配置方式很简单,大家可以自己看下程序并且计算一下初值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#define MODE_QUICK
#define F_TM F0
#define TIMER0_ENABLE TL0=TH0; TR0=1;
#define TIMER0_DISABLE TR0=0;
sbit ACC0= ACC^0;
sbit ACC1= ACC^1;
sbit ACC2= ACC^2;
Delay2cp(35);
//(96-26)/2,循环共
占用26个指令周期
}
while(--temp)
//在指定的
时间内搜寻结束位。
{
Delay2cp(1);
if(RXD)break;
//收到结束位便退出
}
return Output;
}
//延时程序*
void Delay2cp(unsigned char i)
TH0=0xA0;
//预值为256-96=140,十六进制A0
TL0=TH0;
TR0=0; TF0=0; ET0=1; EA=1;
//在发送或接收才开始使用
//允许定时器0中断 //中断允许
总开关
}
//接收一个字符
uchar RByte()
{
uchar Output=0;
uchar i=8;
TR0=1;
//从串口读一个字节
uchar RByte(void)
{
uchar Output=0;
uchar i=8;
uchar temp=RDDYN;
//发送8位数据位
Delay2cp(RDDYN*1.5);
//此处注意,等过起始位
while(i--)
{
Output >>=1;
if(RXD) Output =0x80; //先收低位
别的晶振频率大家自已去算吧。
现在就以11.0592M的晶振为例,谈谈三种模拟串口的方法。
方法一:延时法
通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期。
#define uchar unsigned char
sbit P1_0 = 0x90;
sbit P1_1 = 0x91;
sbit ACC3= ACC^3;
sbit ACC4= ACC^4;
sbit ACC5= ACC^5;
第5页
sbit ACC6= ACC^6; sbit ACC7= ACC^7; void IntTimer0() interrupt 1 { F_TM=1; } //发送一个字符 void PSendChar(unsigned char inch) { #ifdef MODE_QUICK ACC=inch; F_TM=0; BT_SND=0; //start bit TIMER0_ENABLE; //启动 while(!F_TM); BT_SND=ACC0; //先送出低位 F_TM=0; while(!F_TM); BT_SND=ACC1; F_TM=0; while(!F_TM); BT_SND=ACC2; F_TM=0; while(!F_TM); BT_SND=ACC3; F_TM=0; while(!F_TM); BT_SND=ACC4; F_TM=0; while(!F_TM); BT_SND=ACC5; F_TM=0; while(!F_TM); BT_SND=ACC6; F_TM=0; while(!F_TM); BT_SND=ACC7; F_TM=0;
TR0=0;
//停止Timer0
return Output;
P1^0是高电平就退出---第九位是结束位; 而且,两句应该是用一个大括号括起来的吧;
}
//中断1处理程序
void IntTimer0() interrupt 1
{
TM0_FLAG=1;
//设置标志位。
}
//查询传输标志位
void WaitTF0( void )
{
while(--i);
//刚好两个
指令周期。
} 第2页
51单片机模拟串口的方法 此种方法在接收上存在一定的难度,主要是采样定位存在需较准确,另外还必须知道 每条语句的指令周期数。此法可能模拟若干个串口,实际中采用它的人也很多,但如果你用Keil C,本人不建议使用此种方法,上述程序在P89C52、AT89C52、W78E52三种单片机上实验通过。 方法二:计数法 51的计数器在每指令周期加1,直到溢出,同时硬件置溢出标志位。这样我们就可以 通过预置初值的方法让机器每96个指令周期产生一次溢出,程序不断的查询溢出标志来决定是否 发送或接收下一位。
的时间为(12/11.0592)us,那么波特率为9600BPS每位要间融多少个指令周期呢?
指令周期s=(1000000/9600)/(12/11.0592)=96,刚好为一整数,如果为4800BPS则为
96x2=192,如为19200BPS则为48,别的波特率就不算了,都刚好为整数个指令周期,妙吧。至于
51单片机模拟串口的方法 第6页
while(!F_TM); BT_SND=1; F_TM=0; while(!F_TM); TIMER0_DISABLE; //停止timer #else unsigned char ii; ii=0; F_TM=0; BT_SND=0; //start bit TIMER0_ENABLE; //启动 while(!F_TM); while(ii<8) { if(inch&1) { BT_SND=1; } else { BT_SND=0; } F_TM=0; while(!F_TM); ii++; inch>>=1; } BT_SND=1; F_TM=0; while(!F_TM); #endif TIMER0_DISABLE; //停止timer } //接收一个字符 unsigned char PGetChar() { #ifdef MODE_QUICK
的时间,波特率越高,持续的时间越短。如波特率为9600BPS,即每一位传送时间为
1000ms/9600=0.104ms,即位与位之间的延时为为0.104毫秒。单片机的延时是通过执行若干条
指令来达到目的的,因为每条指令为1-3个指令周期,可即是通过若干个指令周期来进行延时的,
单片机常用11.0592M的的晶振,现在我要告诉你这个奇怪数字的来历。用此频率则每个指令周期
位
Delay2cp(39);
//发送8位数据位
while(i--)
{
第1页
TXD=(bit)(input&0x01);
51单片机模拟串口的方法 //先传低位
Delay2cp(36);
input=input>>1;
}
//发送校验位(无)
TXD=(bit)1;
//发送结束
位
Delay2cp(46);
}
51单片机模拟串口的方法 第7页
TIMER0_ENABLE; F_TM=0; while(!F_TM); //等过起始位 ACC0=BT_REC; TL0=TH0; F_TM=0; while(!F_TM); ACC1=BT_REC; F_TM=0; while(!F_TM); ACC2=BT_REC; F_TM=0; while(!F_TM); ACC3=BT_REC; F_TM=0; while(!F_TM); ACC4=BT_REC; F_TM=0; while(!F_TM); ACC5=BT_REC; F_TM=0; while(!F_TM); ACC6=BT_REC; F_TM=0; while(!F_TM); ACC7=BT_REC; F_TM=0; while(!F_TM) { if(BT_REC) { break; } } TIMER0_DISABLE; //停止timer return ACC; #else unsigned char rch,ii;
在中断程序中置标志,程序不断的查询该标志来决定是否发送或接收下一位,当然程序中需对中
断进行初始化,同时编写中断程序。本程序使用Timer0中断。
#define TM0_FLAG P1_2 //设传输标志位
//计数器及中断初始化
void S2INI(void)
{
TMOD =0x02;
//计数器0,方式2
//计数器初始化
void S2INI(void)
{
TMOD =0x02;
//计数器0,方式2
TH0=0xA0;
//预值为256-96=140,十六进制A0
TL0=TH0;
TR0=1;
//开始计数
TF0=0;
Байду номын сангаас
}
void WByte(uchar input)
{
//发送启始位
uchar i=8;
TR0=1;
51单片机模拟串口的方法
void WaitTF0( void )
{
while(!TF0);
TF0=0;
}
接收的程序,可以参考下一种方法,不再写出。这种办法个人感觉不错,接收和发送
都很准确,另外不需要计算每条语句的指令周期数。
方法三:中断法
中断的方法和计数器的方法差不多,只是当计算器溢出时便产生一次中断,用户可以
附:51 IO口模拟串口通讯C源程序(定时器计数法)
#i nclude
sbit BT_SND =P1^0;
sbit BT_REC =P1^1;
/**********************************************
IO 口模拟232通讯程序
使用两种方式的C程序 占用定时器0
**********************************************/