51单片机IO口模拟串口

合集下载

单片机IO口模拟串口程序(发送+接收)

单片机IO口模拟串口程序(发送+接收)

单片机IO口模拟串口程序(发送+接收)前一阵一直在做单片机的程序,由于串口不够,需要用10 口来模拟出一个串口。

经过若干曲折并参考了一些现有的资料,基本上完成了。

现在将完整的测试程序,以及其中一些需要总结的部分贴出来。

程序硬件平台:11.0592M 晶振,STC 单片机(兼容51) /*************************************************************** * 在单片机上模拟了一个串口,使用P2.1作为发送端* 把单片机中存放的数据通过P2.1作为串口TXD 发送出去***************************************************************/#in elude #i nclude #in clude typedef unsigned char uchar; int i;uchar code in fo[]= {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x 55,0x55,0x55,0x5 5 };// SCON: serail mode 1,8-bit UART // T0工作在方式1,十六位定时 // SMOD=1;0xFE; II 定时器0初始值,延时417us ,目的是令模拟串口的波特率为2400bps fosc=11.0592MHz TL0 = 0x7F; II 2400bps fosc=11.0592MHz II TH0= 0xFD; II 定时器0初始值,延时417us ,目的是令模拟串口的波特率为 2400bps fosc=18.432MHzII TL0 = 0x7F; II 定时器0初始值,延时417us ,目的是令模拟串口的波特率为 2400bps fosc=18.432MHz }void WaitTF0( void ) {sbit n ewTXD = P2A 1;〃模拟串口的发送端设为 P2.1 void Uartlnit() {SCON = 0x50; TMOD |= 0x21;PCON |= 0x80; TH0 定时器0初始值,延时417us ,目的是令模拟串口的波特率为TFO=O; THO=OxFE; // 定时器重装初值fosc=11.0592MHz TL0=0x7F; // 定时器重装初值 fosc=11.0592MHzvoid WByte(uchar in put) {//发送启始位 uchar j=8; TR0=1; newTXD=(bit)O; WaitTF0();//发送8位数据位 while (j--) {newTXD=(bit)(i nput&0x01); WaitTF0(); in put= in put>>1; } //发送校验位(无) //发送结束位n ewTXD=(bit)1; WaitTF0(); TR0=0; }void Sendata() {for (i=0;i<="">WByte(i nfo[i]); } }void main() {UartI nit(); while (1) {// TH0 =0xFD; //TL0=0x7F;// }// 定时器重装初值fosc=18.432MHz 定时器重装初值fosc=18.432MHz//先传低位//外层循环,遍历数组}}II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II II IIa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a/************************************************************** ** 模拟接收程序,这个程序的作用从模拟串口接收数据,然后将这些数据发送到实际串口* 在单片机上模拟了一个串口,使用P3.2作为发送和接收端* 以P3.2模拟串口接收端,从模拟串口接收数据发至串口*************************************************************** /#in elude#i nclude#in cludetypedef unsigned char uchar ;//这里用来切换晶振频率,支持11.0592MHz 和18.432MHz//#defi ne F18_432#defi ne F11_0592uchar tmpbuf2[64]={0};//用来作为模拟串口接收数据的缓存struct{uchar recv :6 ;//tmpbuf2 数组下标,用来将模拟串口接收到的数据存放到tmpbuf2中uchar send :6 ;//tmpbuf2 数组下标,用来将tmpbuf2中的数据发送到串口}tmpbuf2_poi nt={0,0};sbit newRXD=P3A2 ; //模拟串口的接收端设为P3.2void Uartl nit(){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送,所以这个初值的意义不大THO=OxFF ;//定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bpsfosc=11.0592MHzTL0=0xA0 ; //定时器0初始值,延时208us,目的是令模拟串口的波特率为9600bps fosc=11.0592MHz#en dif#ifdef F18_432TH 仁0xD8 ; // Baud:2400 fosc=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#en difIE|=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 #en dif#ifdef F18_432TH0=0xFF ;//定时器重装初值fosc=18.432MHzTL0=0x60 ;//定时器重装初值fosc=18.432MHz#en dif}//接收一个字符uchar RByte(){uchar Output=0 ;#ifdef F11_0592THO=OxFF ; //定时器重装初值 TLO=OxAO ; // 定时器重装初值#en dif #ifdef F18_432TH0=0xFF ; // 定时器重装初值fosc=18.432MHzTL0=0x60 ;// 定时器重装初值 fosc=18.432MHz #en difTF0=0 ;WaitTF0(); //等过起始位 //接收8位数据位 while (i--) {Output>>=1 ;if (newRXD)0utput|=0x80 ; // 先收低位WaitTF0(); //位间延时}TR0=0 ; // 停止 Timer0 return Output ; }//向COM1发送一个字符void Sen dChar(uchar byteToSe nd) {SBUF=byteToSe nd ; while (!TI); TI=0 ; }void mai n() {UartI nit(); while (1) {if (tmpbuf2_point.recv!=tmpbuf2_point.send) //差值表示模拟串口接收数据缓存中还有多少个字节的数据未被处理(发送至串口){Sen dChar(tmpbuf2[tmpbuf2_poi nt.se nd++]);uchar i=8 ; TR0=1 ;// 启动 TimerO模拟串口的波特率为 9600bps fosc=11.0592MHz 模拟串口的波特率为 9600bps fosc=11.0592MHz}}}//夕卜部中断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 10 口模拟串口通讯C源程序(定时器计数法)”部分),这种方法在较大程序中,可能会错过起始位(比如起始位到来的时候程序正好在干别的,而没有处于判断起始位到来的状态),或者一直在检测起始位,而没有办法完成其他工作。

STC51单片机IO口模式快速设置

STC51单片机IO口模式快速设置

STC51单⽚机IO⼝模式快速设置STC51单⽚机I0 ⼝模式快速设置-CAL-FENGHAI-(2O2OYEAR-YICAI) JINGBIANSTC51单⽚机IO ⼝模式的快速设置新型51单⽚机STC系列,较传统51单⽚机在性能和速度上有根⽊性的提⾼。

速度提⾼8-12倍;⽚上RAM⼤量增加;⽚上外围模块⼤量增加,等等。

其中10 ⼝的模式增加为4种(传统51只有2中),以P0 ⼝为例:这⾥,每个端⼝新增两个寄存器PxMO, PxMl(x=0,l?2,3)o在设置每⼀个10端的模式时都需要对这两个寄存器进⾏操作。

⽐如:要将设为推挽输出,设为准双向⼝,设为⾼阻输⼊;设为开路模式,都设为准双向⼝,那么需要如下的代码:IO_lnit(){P0M0=0x30;//0011 0000P0Ml=0x90;//1001 0000}这样的设置不便于记忆,很容易写错,且写好的代码可读性差,为此,我们可以通过⼀个宏定义来解决,具体如下:#define PORTO 0#define PORT1 1#define PORT2 2#define PORT3 3#define BITO 0#define BIT1 1#define BIT2 2#define BIT3 3#define BIT4 4#define BIT5 5#define BIT6 6#define BIT7 7#define STANDARD 0#define PP.OUT 1#define ZJN 2#define OD 3#define IOMODE(Port‘bit_n,mode) { \switch(Port)\{\case 0:\switch(mode) { \case STANDARD: P0M0&=^(l?bit_n); POMl&=^(l?bit_n); break; \ case PP_OUT: P0M0&=~(l?bit_n); P0M11 = (l?bit_n);break; \case ZJN: POMO|=(l?bit_n); P0M1 &=~(l?bit_n); break;\ ~case OD: POMO|=(l?bit_n); POMl|=(l?bit_n); break; \} \break;\case 1:\switch(mode) { \case STANDARD: PlMO&=~(l?bit_n); P1M1&⼦(l?bit_n); break; \ case PP_OUT: PlMO&=^(l?bit_n); P1M1|= (l?bit_n);break; \case ZJN: PlMO|=(l?bit_n); P1M1 &=~(l?bit_n); break;\ "case OD: PlMO|=(l?bit_n); PlMl|=(l?bit_n); break; \} \ _ _break;\case 2:\switch(mode) { \case STANDARD: P2M0&=^(l?bit_n); P2Ml&=^(l?bit_n); break; \ case PP_OUT: P2M0&=^(l?bit_n); P2M1| = (l?bit_n); break; \ case Z_IN: P2M0|=(l?bit_n); P2Ml&=zx/(l?bit_n); break;\ ~case OD: P2M0|=(l?bit_n); P2Ml|=(l?bit_n); break; \} \ _ "break;\case 3:\switch(mode) { \case STANDARD: P3MO&=^(l?bit_n); P3Ml&=^(l?bit_n); break; \ case PP_OUT: P3M0&=~(l?bit_n); P3M1|= (l?bit_n);break; \case Z_IN: P3MO|=(l?bit_n); P3M1 &=~(l?bit_n); break; \ ~ case OD: P3M0|=(l?bit_n); P3Ml|=(l?bit_n); break; \} \ _ _break;\}\}有了上⾯的宏定义,在初始化程序中可以直接这样写IOJnit(){IOMODE(PORTO,BIT7/PP_OUT)IOMODE(PORTO,BIT6, STANDARD)IOMODE(PORTO,BIT5/ ZJN)IOMODE(PORTO,BIT4, OD)IOMODE(PORTO,BIT3/ STANDARD)IOMODE(PORTO,BIT2, STANDARD)IOMODE(PORTO/BIT1/ STANDARD)IOMODE(PORTO,BITO, STANDARD)。

51单片机串口设置及应用

51单片机串口设置及应用

51单片机串口设置及应用单片机的串口设置及应用是指通过单片机的串口功能来进行通信的一种方式。

串口通信是一种全双工通信方式,可以实现双向数据传输。

单片机通过串口可以与其他设备进行通信,如计算机、传感器、LCD显示屏等。

1. 串口设置:单片机的串口通信一般需要进行以下设置:(1)串口模式选择:要根据实际情况选择串口工作模式,一般有异步串口和同步串口两种。

(2)波特率设置:串口通信需要设置一个波特率,即数据传输速率。

常见的波特率有9600、19200、115200等,需要与通信的设备保持一致。

(3)数据位设置:设置传输的数据位数,常见的有8位、9位等。

(4)停止位设置:设置停止位的个数,常见的有1位、2位等。

(5)校验位设置:可以选择是否启用校验位,校验位主要用于检测数据传输的正确性。

2. 串口应用:串口通信在很多领域都得到广泛应用,下面列举几个常见的应用场景:(1)串口与计算机通信:通过串口可以实现单片机与计算机的通信,可以进行数据的读写、控制等操作。

例如,可以通过串口将传感器采集到的数据发送给计算机,由计算机进行进一步处理分析。

(2)串口与传感器通信:串口可以与各种传感器进行通信,可以读取传感器采集到的数据,并进行处理和控制。

例如,可以通过串口连接温度传感器,读取实时的温度数据,然后进行温度控制。

(3)串口与LCD显示屏通信:通过串口可以实现单片机与LCD显示屏的通信,可以将需要显示的数据发送给LCD显示屏进行显示。

例如,可以通过串口将单片机采集到的数据以数字或字符的形式显示在LCD上。

(4)串口与外部存储器通信:通过串口可以与外部存储器进行通信,可以读写存储器中的数据。

例如,可以通过串口读取SD卡中存储的图像数据,然后进行图像处理或显示。

(5)串口与其他设备通信:通过串口可以和各种其他设备进行通信,实现数据的传输和控制。

例如,可以通过串口与打印机通信,将需要打印的数据发送给打印机进行打印。

总结:单片机的串口设置及应用是一种实现通信的重要方式。

51单片机模拟spi串行接口程序

51单片机模拟spi串行接口程序
unsigned char SPI_TransferByte(unsigned char val)
{
unsigned char BitCounter;
for(BitCounter=8; BiCounter!=0; BitCounter--)
{ CLK=0;
DataI=0; // write
if(val&0x80) DataI=1;
val<<=1;
CLK=1;
if(DataO)val|=1; // read
}
CLK=0;
return val;
}
sbit CLK= P1^5;
sbit DataI=P1^7;
sbiபைடு நூலகம் DataO=P1^6;
#define SD_Disable() CS=1 //片选关
#define SD_Enable() CS=0 //片选开
val<<=1;
CLK=1;
if(DataO)val|=1; // read
}
CLK=0;
return val;
}
sbit CLK= P1^5;
sbit DataI=P1^7;
sbit DataO=P1^6;
#define SD_Disable() CS=1 //片选关
#define SD_Enable() CS=0 //片选开
unsigned char SPI_TransferByte(unsigned char val)
{
unsigned char BitCounter;
for(BitCounter=8; BiCounter!=0; BitCounter--)
{ CLK=0;

如何使用单片机的单个IO口模拟串口UART输出

如何使用单片机的单个IO口模拟串口UART输出
if(பைடு நூலகம்at & BIT(i)) {
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%。所以用户请严格的控制时间误差在这个范围。

51单片机GPIO口模拟串口通信

51单片机GPIO口模拟串口通信

51单片机GPIO口模拟串口通信随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。

这种情况下下,采集会需要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的51 系列只提供一个串口,那么另一个串口只能靠程序模拟。

本文所说的模拟串口,就是利用51的两个输入输出引脚P1.0 和P1.1,置1 或0 分别代表高低电平,也就是串口通信中所说的位,如起始位用低电平,则将其置0,停止位为高电平,则将其置1,各种数据位和校验位则根据情况置1 或置0。

以11.0592MHz 的晶振为例,通过定时计数器0 产生中断信号来模拟串口电平,下面附上具体源代码。

[cpp]view plaincopy/*Fuction:使用51 单片机GPIO 口模拟串口通信,通过定时计数器0 来产生中断信号SoftwareDesigner:Jason*/#includesbitP1_0=P1;sbitP1_1=P1;#de fine RXD P1_0#de fineTXDP1_1unsignedcharflag;voidinit();voidsend_byte(unsignedchar);unsignedchar rec_byte();voidwait_int();//将从PC 机串口接收到的数据原封不动回传给PC 机voidmain(){unsignedchartemp;init();while(1){if(RI==1){RI=0;temp=rec_byte();send_byte(temp);while(!TI);TI=0;}}}//端口及中断初始化voidinit(){TMOD=0x02;//定时器0,方式2TH0=0xfd;//波特率9600TL0=TH0;TR0=0;//在发送或接收时打开ET0=1;//允许定时器0 中断EA=1;//允许所有中断}//通过串口发送一个字节数据voidsend_byte(unsignedchardat){unsignedchari=8;TR0=1;//开启T0 中断TXD=0;//发送起始位0wait_int();while(i--)//发送8 位数据{TXD=(bit)(dat&0x01);wait_int();dat=dat>>1;}TXD=1;//发送停止位1wait_int();TR0=0;//关闭T0 中断}//通过串口。

IO口模拟UART串口通信

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重新赋值了,配置方式很简单,大家可以自己看下程序并且计算一下初值。

IO口模拟串口三种方法

IO口模拟串口三种方法

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

51单片机IO口工作原理

51单片机IO口工作原理

51单片机IO口工作原理51单片机(英文名为8051 Microcontroller)是一种由Intel公司于1980年推出的8位单片机,广泛应用于嵌入式系统中。

作为一种高性能、低功耗的单片机,其周围有多个IO口(Input/Output ports),可以用来实现数字输入、输出、模拟输入、输出等功能。

下面将详细介绍51单片机IO口的工作原理。

1.51单片机的IO口介绍51单片机共有4个8位的IO口,依次为P0、P1、P2和P3、每个IO 口都是一个8位的寄存器,称为端口寄存器(port register),用于和外部设备进行数据通信。

其中,P0是一个具有双重输入和输出特性的端口,可以配置为输入口或输出口;P1和P3是纯输出端口;P2是输入输出混合端口。

2.IO口的工作模式IO口的工作模式由P0、P1、P2和P3的寄存器位来配置。

每个IO口的寄存器位都有对应的功能和控制位,通过设置这些位可以控制IO口的工作模式和输出状态。

2.1输入模式在输入模式下,IO口作为输入口,接受来自外部器件的信号。

通过将对应的寄存器位设置为1,可以将IO口配置为输入模式。

在输入模式下,端口寄存器的位对应的为悬空状态,可以通过主动上拉或下拉方法来确保IO口的状态。

2.2输出模式在输出模式下,IO口作为输出口,通过控制寄存器位的值可以输出高电平或低电平信号。

将对应的寄存器位设置为0,可以将IO口配置为输出模式。

在输出模式下,直接修改端口寄存器的位即可改变IO口的输出状态。

对于纯输出端口,即P1和P3,更方便地改变IO口的状态可以通过直接操作对应的位。

2.3产生中断IO口还可以通过设置为中断产生源的方式来实现中断功能。

在输入模式下,将对应的寄存器位设置为1,即可配置IO口为中断输入。

当IO口检测到中断触发条件(例如边沿触发、电平触发等),会触发相应的中断服务程序(ISR)。

3.IO口的读取和写入操作为了读取和写入IO口的状态,可以直接访问相应的寄存器。

51单片机模拟串口的三种方法

51单片机模拟串口的三种方法

//先传低位
} //查询计数器溢出标志位 void WaitTF0( void ) { while(!TF0); TF0=0; } 接收的程序,可以参考下一种方法,不再写出。这种办法个人感觉不错,接收和 都很准确,另外不需要计算每条语句的指令周期数。 方法三:中断法
中断的方法和计数器的方法差不多,只是当计算器溢出时便产生一次中断,用户 在中断程序中置标志,程序不断的查询该标志来决定是否发送或接收下一位,当然程 断进行初始化,同时编写中断程序。本程序使用Timer0中断。 #define TM0_FLAG P1_2 //设传输标志位 //计数器及中断初始化 void S2INI(void) { TMOD =0x02; //计数器0,方式2 TH0=0xA0; //预值为256-96=140,十六进制A0 TL0=TH0; TR0=0; //在发送或 接收才开始使用 TF0=0; ET0=1; //允许定时
//发送启始
位 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 Delay2cp(35); 占用26个指令周期 } while(--temp) 时间内搜寻结束位。 { Delay2cp(1); if(RXD)break; } return Output;

51单片机IO口线模拟IIC总线3部曲之第3部

51单片机IO口线模拟IIC总线3部曲之第3部

本文是对第1,2部的使用说明。

若有错误之处请不吝赐教。

IIC底层驱动包使用说明一:说明:(1) 本软件包是使用51单片机IO口线来模拟IIC总线。

适用于12T周期单片机。

若想移植到单T周期单片机,请自行修改。

(2) IIC总线时钟是通过软件延时的方法产生的,所以对不同频率的时钟,需要做一些调整。

(3) 本驱动是IIC最底层的驱动函数,请勿随意改动本驱动。

(4) 本驱动对外只有两个函数可供使用。

一个是“写多字节函数”IICMCUSendStr(),另一个是“先写多字节,然后重新启动总线写一字节,最后接收多字节函数”IICMCUSendStrSendByteRcvStr()。

关于这两个函数的说明请见第三部分,函数详解。

(5) 针对不同的IIC器件读写时序的不同,您应该自己编写IIC器件的驱动。

二:移植方法:使用时有3个地方需要修改,以实现移植。

SDA,SCL和N_12MHz,这三个变量都在IICLowDriver.H文件中。

并且它们定义在文件最开始的位置。

SDA:IIC数据线。

请根据您的硬件设置来选择正确的IO口。

SCL:IIC时钟线。

请根据您的硬件设置来选择正确的IO口。

N_12MHz:所用时钟频率F(单位MHz)与12MHz的比值。

该变量关系到IIC总线时序的正确与否,一定要设置正确。

其取值见下表。

时钟频率F取值范围(MHz)0 ≤ F ≤ 1212 < F ≤ 2424 < F ≤ 3636 < F ≤ 48N_12MHz取值1234只要设置好这三个变量,就可以方便的使用IIC总线了。

为增加移植时的安全性,这三个变量用了预处理命令,移植时请勿改动预处理命令。

三:函数详解。

1、向IIC总线发送多字节数据函数(对外接口)本函数用于IIC器件的写操作。

//-------------------------------------------------------------------------------////函数名称:IICMCUSendStr//函数功能:向IIC总线发送多字节数据。

STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码

STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码

STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码STC 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码原文:(改自周立功软件包)#include <reg51.h>#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intextern void Delay1us(unsigned char );sbit SDA=P1^6; /*模拟I2C数据传送位*/sbit SCL=P1^7; /*模拟I2C时钟控制位*/bit ack; /*应答标志位*//************************************************************** *****起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.*************************************************************** *****/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/Delay1us(1);SCL=1;Delay1us(5); /*起始条件建立时间大于4.7us,延时*/SDA=0; /*发送起始信号*/Delay1us(5); /* 起始条件锁定时间大于4μs*/SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay1us(2);}/************************************************************** *****结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.*************************************************************** *****/void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/Delay1us(1); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4us*/Delay1us(5);SDA=1; /*发送I2C总线结束信号*/Delay1us(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

51单片机模拟串口的三种方法

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) //在指定的时间内搜寻结束位。

89C51 单片机O 口模拟串行通信的实现方法

89C51 单片机O 口模拟串行通信的实现方法

89C51 单片机I/O 口模拟串行通信的实现方法·严天峰·目前普遍采用的MCS51 和PIC 系列单片机通常只有一个(或没有)UART异步串行通信接口,在应用系统中若需要多个串行接口(例如在多机通信系统中,主机既要和从机通信又要和终端通信)的情况下,通常的方法是扩展一片8251 或8250 通用同步/异步接收发送芯片(USART),需额外占用单片机I/O 资源。

本文介绍一种用单片机普通I/O 口实现串行通信的方法,可在单片机的最小应用系统中实现与两个以上串行接口设备的多机通信。

1.串行接口的基本通信方式.串行接口的有异步和同步两种基本通信方式。

异步通信采用用异步传送格式,如图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。

根据数据传送的波特率即字节中每一位的传送时间,我们便可用普通I/O 口来模拟实现串行通信的时序。

2.硬件电路89C51 单片机通过普通I/O 口与PC 机RS232 串口实现通信的硬件接口电路如图2 所示。

由于PC 系列微机串行口为RS232C 标准接口,与输入、输出均采用TTL 电平的89C51 单片机在接口规范上不一致,因此TTL电平到RS232 接口电平的转换采用MAXIM 公司的MAX232 标准RS232接口芯片,该芯片可以用单电压(+5V)实现RS232接口逻辑“1”(-3V~15V)和逻辑“0”(+3V~15V)的电平转换。

51单片机串口通信

51单片机串口通信

51单片机串口通信串行口通信是一种在计算机和外部设备之间进行数据传输的通信方式,其中包括了并行通信、RS-232通信、USB通信等。

而在嵌入式系统中,最常见、最重要的通信方式就是单片机串口通信。

本文将详细介绍51单片机串口通信的原理、使用方法以及一些常见问题与解决方法。

一、串口通信的原理串口通信是以字节为单位进行数据传输的。

在串口通信中,数据传输分为两个方向:发送方向和接收方向。

发送方将待发送的数据通过串行转并行电路转换为一组相对应的并行信号,然后通过串口发送给接收方。

接收方在接收到并行信号后,通过串行转并行电路将数据转换为与发送方发送时相对应的数据。

在51单片机中,通过两个寄存器来实现串口通信功能:SBUF寄存器和SCON寄存器。

其中,SBUF寄存器用于存储要发送或接收的数据,而SCON寄存器用于配置串口通信的工作模式。

二、51单片机串口通信的使用方法1. 串口的初始化在使用51单片机进行串口通信之前,需要进行串口的初始化设置。

具体的步骤如下:a. 设置波特率:使用波特率发生器,通过设定计算器的初值和重装值来实现特定的波特率。

b. 串口工作模式选择:设置SCON寄存器,选择串行模式和波特率。

2. 发送数据发送数据的过程可以分为以下几个步骤:a. 将要发送的数据存储在SBUF寄存器中。

b. 等待发送完成,即判断TI(发送中断标志位)是否为1,如果为1,则表示发送完成。

c. 清除TI标志位。

3. 接收数据接收数据的过程可以分为以下几个步骤:a. 等待数据接收完成,即判断RI(接收中断标志位)是否为1,如果为1,则表示接收完成。

b. 将接收到的数据从SBUF寄存器中读取出来。

c. 清除RI标志位。

三、51单片机串口通信的常见问题与解决方法1. 波特率不匹配当发送方和接收方的波特率不一致时,会导致数据传输错误。

解决方法是在初始化时确保两端的波特率设置一致。

2. 数据丢失当发送方连续发送数据时,接收方可能会出现数据丢失的情况。

51单片机汇编模拟串口通信程序

51单片机汇编模拟串口通信程序

51单片机汇编模拟串口通信程序T2作为波特率控制UART_RXD是硬中断0或1 口,如果能进入中断,说明该线有一个起始位产生,进入中断后调用下面的接收程序。

退出硬中断之前还需要将硬中断标志重新复位。

UART_TXD是任何其它IO即可。

UART_SEND:P USH IEP USH DPHP USH DPLP USH PSWP USH 00HP USH ACCCLR EASETB UART_TXD ;START BITMOV R0,ACLR TR2 ;TR2置1,计数器2启动,时间计数启动。

MOV A,RCAP2L;计数器2重新装载值MOV TL2,A ;置计数器2初值;T2需要重新装载MOV A,D PH CLR TF2MOV A,RCA P2HMOV TH2,AMOV A,R0SETB TR2 ;TR2 置1,计数器JNB TF2,$CLR TF2JNB TF2,$CLR TF2CLR UART_TXD ;START BITJNB TF2,$CLR TF2JNB TF2,$CLR TF2MOV R0,#08HUART_SEND_L OOP:RRC AMOV UART_TXD,C ;8 BIT JNB TF2,$CLR TF2DJNZ RO,UART_SEND_L OOP SETB UART_TXD ;END BIT JNB TF2,$CLR TF2JNB TF2,$CLR TF2POP ACCPOP OOHPOP PSWPOP DPLPOP DPHPOP IERET....;;;;;;; UART_REC:P USH IEP USH DPHP USH DPLCLR EACLR TR2 ;TR2置1,计数器2启动,时间计数启动。

MOV A,RCAP2L;计数器2 重新装载值CLR TF2MOV TL2,A ;置计数器2初值;T2需要重新装载MOV A,DPHMOV A,RCA P2HMOV TH2,AJB UART_RXD,$ ;RECSETB TR2 ;TR2置1,计数器2启动,时间计数启动。

51单片机串口工作方式0和1

51单片机串口工作方式0和1

方式 1 用于串行通信 例3:8031串行口双工方式收发 ASCII 字符,最高 1 位用来作奇偶校验位,采用奇校验方式, 波特率为 1200 。
• 工作方式
• REN = 1,允许串行口接收数据 • REN = 0,禁止串行口接收数据 由软件置位或清除
7.1.2 特殊功能寄存器PCON
• 串行数据传送速率控制寄存器 —— PCON
b7 SMOD
b6
b5
b4
b3
b2
b1
b0
GF1 GF2
地址:87H SMOD = 0,定义波特率不变 SMOD = 1,定义波特率加倍 注:PCON 寄存器的地址为87H, 仅 b7 位有用,不可位寻址。
串口工作方式
5.1 方式0 同步移位寄存器方式,比特率固定为fosc/12。 常用于外接移位寄存器,以扩展并行I/O口,SM2位必须为0 。 1.方式0发送: 当CPU执行写入发送缓冲器SBUF的指令时,串行口即把SBUF 中的8位数据以fosc/12的固定比特率从RXD引脚串行输出,低 位在先,TXD引脚输出同步移位脉冲,发送完8位数据置“1” 中断标志位TI
• 电路图
8031
RXD TXD P1.0 DATA CLK
CD4094
TBS
方式 0 用于扩展并行 I/O口
• 编程
ORG 0000H LJMP MAIN ORG 0023H LJMP SBR MAIN: MOV SCON,#00H; 方式 0,TI = 0 SETB EA SETB ES MOV A,#80H ; 初值,左边 LED 亮 CLR P1.0 ; CD4094 输出并口关闭 MOV SBUF,A ; 数据传出,产生中断 LOOP: SJMP $
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

论坛新老朋友们。

祝大家新年快乐。

在新的一年开始的时候,给大家一点小小的玩意。

工程师经常碰到需要多个串口通信的时候,而低端单片机大多只有一个串行口,甚至没有串口。

这时候无论是选择高端芯片,还是更改系统设计都是比较麻烦的事。

我把以前搞的用普通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; //0
delay_bps();
SBUF1_bit1 = RXD1; //1
delay_bps();
SBUF1_bit2 = RXD1; //2
delay_bps();
SBUF1_bit3 = RXD1; //3
delay_bps();
SBUF1_bit4 = RXD1; //4
delay_bps();
SBUF1_bit5 = RXD1; //5
delay_bps();
SBUF1_bit6 = RXD1; //6
delay_bps();
SBUF1_bit7 = RXD1; //7
delay_bps();
return(SBUF1) ; //返回读取的数据
}
void putchar2(unsigned char input) //模拟发送一个字节数据
{
SBUF1 = input;
TXD1 = 0; //起始位
delay_bps();
TXD1 = SBUF1_bit0; //0
delay_bps();
TXD1 = SBUF1_bit1; //1
delay_bps();
TXD1 = SBUF1_bit2; //2
delay_bps();
TXD1 = SBUF1_bit3; //3
delay_bps();
TXD1 = SBUF1_bit4; //4
delay_bps();
TXD1 = SBUF1_bit5; //5
delay_bps();
TXD1 = SBUF1_bit6; //6
delay_bps();
TXD1 = SBUF1_bit7; //7
delay_bps();
TXD1 = 1; //停止位
delay_bps();
}
3、实现串行通讯。

在主程序文件中直接调用上面的getchar2()和putchar2()函数,配合电脑的串行口,即可实现串行通讯功能
4、请参考完整程序文件,不过此串行通讯为程序查询方式,如果程序中有中断程序,很可能会造成接收数据丢失。

在一会继续发一个帖子,把利用中断方式串行通讯程序也发来给大家看看。

注意问题:1、波特率是可以有误差,但每个位的误差,不能大于3%2、中断可能
会改变延时的时间。

如果你的中断里的程序较长,应该在模拟串口接收和发送时禁止中断。

3、接收时要延时1.5个的位时间(一个起始位+半个数据位)。

使数据位的采样点尽量放在数据位的中间。

(本文转自电子工程世界:/mcu/2012/0804/article_9759.html)。

相关文档
最新文档