当前位置:文档之家› 用定时器 T0 或 T1 模拟串行口程序

用定时器 T0 或 T1 模拟串行口程序

用定时器 T0 或 T1 模拟串行口程序
用定时器 T0 或 T1 模拟串行口程序

/*************************************************************************

用定时器T0 或T1 模拟串行口程序。

最高波特率(12 clock):

本程序收、发波特率相同。

11.059MHz -- 最高波特率收: 9600, 最低波特率:300

30.000MHz -- 最高波特率收: 28800 最低波特率:300

40.000MHz -- 最高波特率收: 38400 最低波特率:300

...

使用说明:

1. 本程序使用一个定时器和任意2 个I/O 口模拟一个串行口。

2. 1位起始位,8位数据位,1位停止位。发数据位时先发低位。

3. 支持半双工通讯。收、发波特率相同。

4. 应把定时器中断优先级设置为最高级。

5. 本程序每接收一个字节后就把它放到一个队列缓冲区中(也可使用环行缓冲区),

待缓冲区满后,将缓冲区中的内容原样发回。这是为了测试多字节连续收发的

能力和简化程序。实际应用中应防止缓冲区溢出。

6. 由接收转换到发送时要先调用soft_send_enable ();

由发送转换到接收时要先调用 soft_receive_enable ()。

7. 发送最后一个字节后如果要立刻转为接收,必须等待最后一个字节后发送完毕 w hile ( rs_f_TI == 0) ; // 等待最后一个字节发送完毕

**************************************************************************

编程说明:

----------------

发送:

由接收转换到发送时要先调用soft_send_enable (), 它为发送做初始化的工作。

以后就可以调用rs_send_byte () 启动发送一个字节的过程。

发送口平时为高电平,rs_send_byte ()函数使发送口变为低电平开始发送起始位; 同时设置和启动定时器,为发送数据位在预定的时刻产生定时器中断。发送数据位和停止位都在定时器的中断服务程序中进行。

中断服务程序中处理4 种情况:发送数据位、发送停止位、发送完毕、处理错误。----------------

接收:

由发送转换到接收时要先调用soft_receive_enable (), 它为接收做初始化的工

作。定时器以3 到4 倍波特率的频率产生中断(参见rs_TE ST0 的定义)检测P C 机发送的起始位。一旦检测到起始位,立刻把定时器产生中断的频率调整到与波特率相同,准备在下一个定时器中断中接收第1 个数据位。

中断服务程序中处理以下情况:

1. 收到的是P C 机发送的起始位: 调整定时器产生中断的频率与波特率相同。

2. 收到第8 位数据位: 存储接收到的字节。

3. 收到第1--7 位数据位: 存储到收、发移位暂存器。

4. 收到停止位: 调用soft_recei v e_enable(),检测PC 机发出的下一个起始位。

5. 处理出错的情况。

**************************************************************************/

#i nclude

sfr16 DP TR = 0x82;

typedef unsigned char INT8U;

typedef unsigned int INT16U;

#define YE S 1

#define NO 0

//定义使用哪个定时器, 只可定义一个

//#define TIMER_0

#define TIMER_1

//定义串口收、发送管脚。

sbit rs_TXD = P2^1;

sbit rs_RXD = P2^0;

//根据定时器确定参数

#ifdef TIMER_0

#define TMOD_AND_WORD 0xF0;

#define TMOD_TIME_MODE 0x01;

#define TMOD_COUNT_MODE 0x05; //设置计数模式位sbit TCON_ENABLE_TIMER = TCON^4;

sbit TCON_TFx = TCON^5; //中断标志位

sbit IE_ETx = IE^1; //中断允许位为E T0

sbit IP_PTx = IP^1; //中断优先级

sfr rs_timerL = 0x8A; //TL0

sfr rs_timerH = 0x8C; //TH0

#endif

#ifdef TIMER_1

#define TMOD_AND_WORD 0x0F;

#define TMOD_TIME_MODE 0x10;

#define TMOD_COUNT_MODE 0x50; //设置计数模式位sbit TCON_ENABLE_TIMER = TCON^6; //

sbit TCON_TFx = TCON^7; //中断标志位

sbit IE_ETx = IE^3; //中断允许位为E T1

sbit IP_PTx = IP^4; //中断优先级

sfr rs_timerL = 0x8B; //TL1

sfr rs_timerH = 0x8D; //TH1

#endif

INT8U bdata rs_BUF; //串行收、发时用的移位暂存器。

sbit rs_BUF_bit7 = rs_BUF^7; //移位暂存器的最高位。

INT8U rs_shift_count; //移位计数器。

INT8U bdata rsFlags;

sbit rs_f_TI = rsFlags^0; //0:正在发送; 1: 一个字符完毕

sbit rs_f_RI_enable = rsFlags^1; //0:禁止接收; 1:允许接收

sbit rs_f_TI_enable = rsFlags^2; //0:禁止发送; 1:允许发送

//选择以下一个晶体频率

//#define Fosc 6000000 //6MHz

#define Fosc 11059200 //11.059MHz

//#define Fosc 12000000

//#define Fosc 18432000

//#define Fosc 20000000

//#define Fosc 24000000

//#define Fosc 30000000

//#define Fosc 40000000

//选择以下一个波特率:

//#efine Baud 300 //11.059MHz时,baud 最低为300

//#define Baud 1200

//#define Baud 2400

//#define Baud 4800

#define Baud 9600

//#define Baud 14400

//#define Baud 19200

//#define Baud 28800

//#define Baud 38400

//#define Baud 57600

//收、发一位所需定时器计数

#define rs_FULL_BIT0 ((Fosc/12) / Baud)

#define rs_FULL_BIT (65536 - rs_FULL_BIT0)

#define rs_FULL_BIT_H rs_FULL_BIT >> 8 //收、发一位所需定时器计数高位#define rs_FULL_BIT_L (rs_FULL_BIT & 0x00FF) //收、发一位所需定时器计数低位

//检测起始位的时间间隔所需定时器计数

#define rs_TE ST0 rs_FULL_BIT0 / 4 //波特率较低时可以除以3 或除以2

#define rs_TE ST ((~rs_TE ST0))

#define rs_TE ST_H rs_TE ST >> 8 //高位

#define rs_TE ST_L rs_TE ST & 0x00FF //低位

//发送起始位所需定时器总计数

#define rs_START_BIT 0xFFFF - (Fosc/12/Baud) + 0x28

#define rs_START_BIT_H rs_START_BIT >> 8 //发送起始位所需定时器计数高位#define rs_START_BIT_L rs_START_BIT & 0x00FF //发送起始位所需定时器计数低位

#define rs_RE CEIV E_MAX 128 //最大接收长度

INT8U idata rs232buffer[rs_RE CEIV E_MAX]; //收、发缓冲区

INT16U ReceiveP oint; //接收数据存储指针

void soft_rs232_interrupt( void );

#ifdef TIMER_0

void timer0 (void) interrupt 1 using 3

{

if (rs_RXD == 0 | rs_shift_count > 0)

{ soft_rs232_interrupt(); }

else

{

rs_timerH = rs_TE ST_H;

rs_timerL = rs_TE ST_L;

}

}

#endif

#ifdef TIMER_1

void timer1 (void) interrupt 3 using 3

{

if (rs_RXD == 0 | rs_shift_count > 0)

{ soft_rs232_interrupt(); }

else

{

rs_timerH = rs_TE ST_H;

rs_timerL = rs_TE ST_L;

}

}

#endif

/***************************************/

void soft_rs232_init (void) //串口初始化

{

TCON_ENABLE_TIMER = 0; //停止定时器

TMOD &= TMOD_AND_WORD;

TMOD |= TMOD_TIME_MODE;

rs_RXD = 1; //接收脚置成高电平

rs_TXD = 1; //发射脚置成高电平

IP_PTx = 1; //置中断优先级为高

IE_ETx = 1; //允许定时器中断

}

void soft_receive_init() //监测起始位

{

TCON_ENABLE_TIMER = 0; //停止定时器

rs_timerH = rs_TE ST_H;

rs_timerL = rs_TE ST_L;

rs_shift_count = 0;

TCON_ENABLE_TIMER = 1; //启动定时器

}

void soft_receive_enable() //允许接收

{

rs_f_RI_enable = 1; //允许接收

rs_f_TI_enable = 0; //禁止发送

soft_receive_init(); //监测起始位, RXD 下降沿触发接收字节过程. }

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_rs232_interrupt( void )

{

/************************ 接收****************************/

if (rs_f_RI_enable == 1)

{

if (rs_shi f t_count == 0) //移位计数器==0, 表示检测到起始位的起点{

if ( rs_RXD == 1 )

{

soft_recei v e_enable (); //起始位错, 从新开始

}

else

{

//下次中断在数据位或停止位中的某时刻发生

rs_timerL += rs_FULL_BIT_L + 0x10;

rs_timerH = rs_FULL_BIT_H;

rs_shi f t_count++;

rs_BUF = 0; //清移位缓冲变量

}

}

else

{

rs_timerL += rs_FULL_BIT_L; //下次中断在数据位或停止位中发生

rs_timerH = rs_FULL_BIT_H;

rs_shi f t_count++; //2--9:数据位10:停止位

if ( rs_shi f t_count == 9)

{

rs_BUF = rs_BUF >> 1; //接收第8位

rs_BUF_bit7 = rs_RXD;

if( Recei v eP oint < rs_RECEIVE_MAX)

{ //保存收到的字节

rs232buffer[Recei v eP oint++] = rs_BUF;

}

else

{

rs_f_RI_enable = 0; //缓冲区满, 禁止接收

}

}

else

{

if (rs_shi f t_count < 9 ) //收到的是数据位1 -- 7

{

rs_BUF = rs_BUF >> 1;

rs_BUF_bit7 = rs_RXD;

}

else

{ //收到停止位,继续检测P C 机发出的下一个起始位soft_recei v e_init();

}

}

}

TCON_TFx = 0; //清定时器中断标志

}

else

{

/************************ 发送****************************/

if (rs_f_TI_enable == 1)

{

rs_timerL += rs_FULL_BIT_L;//下次中断在数据位的末尾时刻rs_timerH = rs_FULL_BIT_H;

rs_shi f t_count--; //0:停止位末尾时刻到

//1:发送停止位

//2--9:发送数据位

if (rs_shi f t_count > 9) //错误状态

{

rs_shi f t_count = 9;

rs_BUF = 0xFF;

}

if (rs_shi f t_count > 1) //2--9:发送数据位

{

ACC = rs_BUF;

ACC = ACC >> 1;

rs_TXD = CY;

rs_BUF = ACC;

}

else

{

if (rs_shi f t_count == 0) //0:停止位末尾时刻到

{

rs_TXD = 1;

rs_f_TI = 1; //已发送完毕一个字节

}

else

{

rs_TXD = 1; //1:发送停止位

}

}

}

}

}

//由收转到发时,要先调用soft_send_enable ()

void rs_send_byte(INT8U SendByte) //发送一个字节

{

w hile ( rs_f_TI == 0); //等待发送完毕前一个字节

rs_TXD = 1;

rs_timerL = rs_ST ART_BIT_L; //下次中断在起始位的末尾时刻

rs_timerH = rs_START_BIT_H;

rs_BUF = SendByte;

rs_shift_count = 10;

rs_TXD = 0; //发送起始位

rs_f_TI = 0; //清已发送完毕一个字节的标志

}

void initiate_MCU (void) //系统初始化

{

soft_rs232_init(); //串口初始化

E A = 1; //开中断

}

void main (void)

{

//首先发送128 个字节00H--7FH, 然后等待P C 机发送的数据。当收到128 //个字节后,立刻将收到的128 个数据回发送给P C 机,然后继续等待下一个//数据块。

INT8U i;

initiate_MCU(); //系统初始化

soft_send_enable (); //允许发送,禁止接收

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

{

rs_send_byte(i);

}

w hile ( rs_f_TI == 0) ; // 等待最后一个字节发送完毕

w hile(1)

{

soft_receive_enable (); //启动并开始接收,禁止发送

w hile (ReceiveP oint < rs_RE CEIV E_MAX); // 等待接收缓冲区满

soft_send_enable (); //允许发送,禁止接收

for (i=0; i < rs_RE CEIV E_MAX; i++ )

{

rs_send_byte(rs232buffer[i]);

}

w hile ( rs_f_TI == 0) ; //等待最后一个字节发送完毕ReceiveP oint = 0;

}

}

KEIL中如何用虚拟串口调试串口程序

KEIL中如何用虚拟串口调试串口程序 发表于2008/5/7 15:30:22 以前没接触过串口,一直都以为串口很复杂。最近在做一个新项目,用单片机控制GSM模块。单片机和GSM模块接口就是串口。调试完后觉得串口其实很简单。“不过如此”。这可能是工程师做完一个项目后的共同心态吧。下面详细介绍下如何用虚拟串口调试串口发送接收程序。 需要用到三个软件:KEIL,VSPD XP5(virtual serial ports driver xp5.1虚拟串口软件),串口调试助手。 1、首先在KEIL里编译写好的程序。 2、打开VSPD,界面如下图所示: 左边栏最上面的是电脑自带的物理串口。点右边的add pair,可以添加成对的串口。一对串口已经虚拟互联了,如果添加的是COM3、COM4,用COM3发送数据,COM4就可以接收数据,反过来也可以。 3、接下来的一步很关键。把KEIL和虚拟出来的串口绑定。现在把COM3和KEIL 绑定。在KEIL中进入DEBUG模式。在最下面的COMMAND命令行,输入MODE COM3 4800,0,8,1(设置串口3的波特率、奇偶校验位、数据位、停止位,打开COM3串口,注意设置的波特率和程序里设置的波特率应该一样)ASSIGN COM3 SOUT(把单片机的串口和COM3绑定到一起。因为我用的单片机是AT892051,只有一个串口,所以用SIN,SOUT,如果单片机有几个串口,可以选择S0IN,S0OUT,S1IN,S1OUT。)

4、打开串口调试助手 可以看到虚拟出来的串口COM3、COM4,选择COM4,设置为波特率4800,无校验位、8位数据位,1位停止位(和COM3、程序里的设置一样)。打开COM4。 现在就可以开始调试串口发送接收程序了。可以通过KEIL发送数据,在串口调试助手中就可以显示出来。也可以通过串口调试助手发送数据,在KEIL中接收。这种方法的好处是不用硬件就可以调试。这是网上一篇文章介绍的方法,联系我实际的使用做了整理。有用的着的人就不用继续摸索了

单片机模拟串口

随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。这种情况下下,采集会需要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的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 char sbit 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; } //发送校验位(无)

用单片机普通I_O口模拟串口的一种方法

电子报/2005年/12月/18日/第011版 单片机应用 用单片机普通I/O口模拟串口的一种方法 南昌李春玲 MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD (P3.0)和TXD(P3.1)与外设进行全双工的串行异步通信。串行端口有四种基本工作方式:方式0主要用于外接移位寄存器,以扩展单片机的I/O接口;方式1多用于双机之间或与外设的通信;方式2、方式3除有方式1的功能外,还可用作主从式多机通信,构成分布式多机系统。 在应用系统中,若需要多个串口,且各串口工作方式要求不同,如:通信波特率不一样,通常的方法是扩展一片可编程串行接口芯片,如8251或8250,但这样增加了硬件开销,且需要占用较多的I/O资源。本文介绍一种用单片机普通I/O口模拟串口的方法。 以A、B两个单片机之间的串行通信为例,电路如图1所示。使用了P1口中的3条普通I/O口,其中P1.0为串行发送端(模拟TXD),P1.1为串行接收端(模拟RXD),P1.2作为对方单片机的中断申请信号INTO的输入线(模拟内部串行口中断源RI/TI)。 串行通信信息帧的发送与接收由软件编程实现。工作过程如下(以A机发送、B机接收为例): 1.A机从P1.2口输出中断申请信号。 2.A机通过P1.0口发送一帧模拟信息。串行通信采用异步传送格式:包括1位起始位(低电平)、7或8位数据编码、1位奇偶校验位(可不要)、1位停止位(高电平)。串行通信中,如果数据传送的波特率为1200bps,则每位信息维持时间为0.833ms。 程序段TTXD完成上述发送功能。信息帧为10位(1位起始位、8位数据编码、无奇偶校验位、1位停止位)。 3.B机接收到INTO的中断申请信号后,自动进入中断服务程序,同步进行模拟异步接收。当P1.1口从高变低时,说明一帧开始,然后依次接收8位数据编码,采样数据在每一位的中间进行,故接收与发送要错开半位,最后检测到高电平后,跳出中断。一次中断完成一帧信息的接收,获得一个字节的数据。 INTO的中断服务程序段RRXD完成上述接收功能。 程序清单如下: TTXD:MOV A,#DATA;发送字节送A CLR P1.2;送中断申请信号 SETB P1.0 LCALL DELAY417

单片机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,0x55,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.432MHz II 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 ,目的是令模拟串口的波特率为

STC单片机虚拟串口发送程序(超简单)

STC单片机(STC12C5A32S)虚拟串口发送程序 //虚拟串口发送子函数 void Uart(uint8 a) { ACC=a; //TXD3是已经定义的任意的发送端口 TR1=1; TXD3=0; //发送起始位 while(TF1==0); TF1=0; //TF1必须清零,因为只有启用T1中断才会自动清零 TXD3=ACC0; //发送8个位也可以用移位来发送,ACC0-ACC7也必须先定义 while(TF1==0); //表示ACC的8个位,如果用移位发送,就不用这样定义。 TF1=0; TXD3=ACC1; while(TF1==0); TF1=0; TXD3=ACC2; while(TF1==0); TF1=0; TXD3=ACC3; while(TF1==0); TF1=0; TXD3=ACC4; while(TF1==0); TF1=0; TXD3=ACC5; while(TF1==0); TF1=0; TXD3=ACC6; while(TF1==0); TF1=0; TXD3=ACC7; while(TF1==0); TF1=0; TXD3=1; //发送停止位 while(TF1==0); TF1=0; TR1=0; } 该子函数使用T1定时器,T0也可以。采用8位自动重装,重装值为A0 Main() { TMOD = 0x21; //T0:模式1,16位定时器。T1:模式2,8位定时器,自动重装AUXR &= 0x3f; //定时器0和定时器1与普通8051定时器一样(不同的单片机设置可能

不同) TL1 = 0xa0; //虚拟串口波特率:9600 TH1 = 0xa0; ET0 = 1; ET1 = 0; //T1中断一定不要使用,要不接收会错误 TR0 = 1; TR1 = 0; Uart(0xaa); //0xaa是发送的数据,如果接收有误,在发送一个字节后可加点延时//延时 While(1); //具体程序此处省略 } 注:因本人实验的硬件不需要模拟串口来接收数据,故没给出虚拟串口接收程序。 以上程序已验证成功。

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

51单片机模拟spi串行接口程序 51单片机模拟spi串行接口程序,在keilc51下编写 sbit CS=P3^5; 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; 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;

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; 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; sbit DataO=P1^6; #define SD_Disable() CS=1 //片选关 #define SD_Enable() CS=0 //片选开

51单片机IO口模拟串口通讯C源程序

51单片机IO口模拟串口通讯C源程序 #include sbit BT_SND =P1^0; sbit BT_REC =P1^1; /********************************************** IO 口模拟232通讯程序 使用两种方式的C程序占用定时器0 **********************************************/ #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; sbit ACC3= ACC^3; sbit ACC4= ACC^4; sbit ACC5= ACC^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; 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

利用VIRTUAL TERMINAL模拟单片机串口收发实验

利用VIRTUAL TERMINAL模拟单片机串口收发实验 程序 #include //包含头文件 //毫秒级延时函数 void delay(unsigned int x) { unsigned char i; while(x--) { for(i=0;i<120;i++); } } //字符发送函数 void putchar(unsigned char data1) { SBUF=data1; //将待发送的字符送入发送缓冲器 while(TI==0); //等待发送完成 TI=0; //发送中断标志请0 } //字符串发送函数 void putstring(unsigned char *dat) { while(*dat!='\0') //判断字符串是否发送完毕 { putchar(*dat); //发送单个字符 dat++; //字符地址加1,指向先下一个字符 delay(5); } } //主函数 void main(void) { unsigned char c=0; SCON=0x50; //串口方式1 ,允许接收 TMOD=0x20; //T1工作于方式2 PCON=0x00; //波特率不倍增 TL1=0xfd; //波特率设置 TH1=0xfd; //

EA=1; //开总中断 ES=1; //开串口接收中断 //TI = 0; TR1=1; //定时器开启 delay(200); putstring("abc\r\n"); //串口向终端发送字符串,结尾处回车换行putstring("----------------------\r\n"); delay(50); while(1) { } } // void revdata(void) interrupt 4 { unsigned char temp; if(RI==0) return; //如果没有接收中断标志,返回 ES=0; //关闭串口中断 RI=0; //清串行中断标志位 temp=SBUF; //接收缓冲器中的字符 putchar(temp); //将接收的字符发送出去 ES=1; //开启串口中断 }

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

51单片机汇编模拟串口通信程序 T2作为波特率控制UART_RXD 是硬中断0或1口,如果能进入中断,说明该线有一个起始位产生,进入中断后调 用下面的接收程序。退出硬中断之前还需要将硬中断标志重新复位。 UART_TXD是任何其它IO即可。 UART_SEND: PUSH IE PUSH DPH PUSH DPL PUSH PSW PUSH 00H PUSH ACC CLR EA SETB UART_TXD ;START BIT MOV R0,A CLR TR2 ;TR2置1,计数器2启动,时间计数启动。 MOV A,RCAP2L;计数器2重新装载值 MOV TL2,A ;置计数器2初值;T2需要重新装载 MOV A,DPH MOV A,RCAP2H MOV TH2,A MOV A,R0 SETB TR2 ;TR2置1,计数器 JNB TF2,$ CLR TF2 JNB TF2,$ CLR TF2 CLR UART_TXD ;START BIT JNB TF2,$

CLR TF2 JNB TF2,$ CLR TF2 MOV R0,#08H UART_SEND_LOOP: RRC A MOV UART_TXD,C ;8 BIT JNB TF2,$ CLR TF2 JNB TF2,$ CLR TF2 DJNZ R0,UART_SEND_LOOP SETB UART_TXD ;END BIT JNB TF2,$ CLR TF2 JNB TF2,$ CLR TF2 POP ACC POP 00H POP PSW POP DPL POP DPH POP IE RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; UART_REC: PUSH IE PUSH DPH PUSH DPL CLR EA

用定时器 T0 或 T1 模拟串行口程序

/************************************************************************* 用定时器T0 或T1 模拟串行口程序。 最高波特率(12 clock): 本程序收、发波特率相同。 11.059MHz -- 最高波特率收: 9600, 最低波特率:300 30.000MHz -- 最高波特率收: 28800 最低波特率:300 40.000MHz -- 最高波特率收: 38400 最低波特率:300 ... 使用说明: 1. 本程序使用一个定时器和任意2 个I/O 口模拟一个串行口。 2. 1位起始位,8位数据位,1位停止位。发数据位时先发低位。 3. 支持半双工通讯。收、发波特率相同。 4. 应把定时器中断优先级设置为最高级。 5. 本程序每接收一个字节后就把它放到一个队列缓冲区中(也可使用环行缓冲区), 待缓冲区满后,将缓冲区中的内容原样发回。这是为了测试多字节连续收发的 能力和简化程序。实际应用中应防止缓冲区溢出。 6. 由接收转换到发送时要先调用soft_send_enable (); 由发送转换到接收时要先调用 soft_receive_enable ()。 7. 发送最后一个字节后如果要立刻转为接收,必须等待最后一个字节后发送完毕 w hile ( rs_f_TI == 0) ; // 等待最后一个字节发送完毕 ************************************************************************** 编程说明: ---------------- 发送: 由接收转换到发送时要先调用soft_send_enable (), 它为发送做初始化的工作。 以后就可以调用rs_send_byte () 启动发送一个字节的过程。 发送口平时为高电平,rs_send_byte ()函数使发送口变为低电平开始发送起始位; 同时设置和启动定时器,为发送数据位在预定的时刻产生定时器中断。发送数据位和停止位都在定时器的中断服务程序中进行。 中断服务程序中处理4 种情况:发送数据位、发送停止位、发送完毕、处理错误。---------------- 接收: 由发送转换到接收时要先调用soft_receive_enable (), 它为接收做初始化的工 作。定时器以3 到4 倍波特率的频率产生中断(参见rs_TE ST0 的定义)检测P C 机发送的起始位。一旦检测到起始位,立刻把定时器产生中断的频率调整到与波特率相同,准备在下一个定时器中断中接收第1 个数据位。 中断服务程序中处理以下情况: 1. 收到的是P C 机发送的起始位: 调整定时器产生中断的频率与波特率相同。 2. 收到第8 位数据位: 存储接收到的字节。 3. 收到第1--7 位数据位: 存储到收、发移位暂存器。 4. 收到停止位: 调用soft_recei v e_enable(),检测PC 机发出的下一个起始位。 5. 处理出错的情况。 **************************************************************************/

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; //0 delay_bps(); SBUF1_bit1 = RXD1; //1 delay_bps(); SBUF1_bit2 = RXD1; //2

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

前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口。经过若干曲折并参考了一些现有的资料,基本上完成了。现在将完整的测试程序,以及其中一些需要总结的部分贴出来。 程序硬件平台:11.0592M晶振,STC单片机(兼容51) /*************************************************************** * 在单片机上模拟了一个串口,使用P2.1作为发送端 * 把单片机中存放的数据通过P2.1作为串口TXD发送出去 ***************************************************************/ #include #include #include typedef unsigned char uchar; int i; uchar code info[] = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x5 5 }; sbit newTXD = P2^1;//模拟串口的发送端设为P2.1 void UartInit() { SCON = 0x50; // SCON: serail mode 1, 8-bit UART TMOD |= 0x21; // T0工作在方式1,十六位定时 PCON |= 0x80; // SMOD=1; TH0 = 0xFE; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=11.0592MHz TL0 = 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) {

模拟串口的C语言源程序代码

模拟串口的C语言源程序代码 本程序是模拟串口硬件机制写的,使用时可设一定时中断,时间间隔为 1/4 波特率,每中断一次调用一次接收函数,每中断4 次调用一次发送函数,不 过.对单片机来说时钟并须要快.要知道9600 的波特率的每个BIT 的时间间隔是 104us.而单片机中断一次压栈出栈一次的时间是20us 左右(标准的51 核12M 晶体)这样处理时间就要考虑清楚了.呵呵.以下程序是放在定时器中断程序函数内 的 //接收部分sbit JieShou_D= ;//定义接收端口uint8 DingShiJiShu,JieShou_h;//定时计数,接收缓冲器uint16 JieShou_T;//接收临时寄存器bit KaiShi,JieShou_b;// 开始接收标准,接收完成标志 void JieShou(void) //接收函数,每4 次调用接收一位{ if((KaiShi==0) (JieShou_D==0)) //串行开始位到来{ DingShiJiShu=0; //开始定时计数KaiShi=1; JieShou_T=0xffff; //接收临时寄存器置全1 } else if((KaiShi==1) (DingShiJiShu==1)) //第2 次调用,串行数据采样时间到来{ JieShou_T = 1; if(JieShou_D) JieShou_T |=0x8000; } else if(JieShou_T 0x807f ==0x803f) //接收完成JieShou_T=1xxx_xxxx_x011_1111 { KaiShi=0; DingShiJiShu=0; JieShou_h = JieShou_T 7; //右移7 位得到串行数据JieShou_b=1; } if(KaiShi) { DingShiJiShu++; //只在开始接收时定时计数+1 DingShiJiShu =0x03; //每4 次调用接收一位} } //发送部分sbit FaSong_D= ;//定义发送端口uint16 FaSong_h; //发送缓冲区bit FaSong_b; //发送完成标志 void KaiShiFaSong(uint8 fs) //设置发送数据,开始发送{ FaSong_h = fs; FaSong_h = 1; FaSong_h |= 0x0200; //FaSong_h=0000_001x_xxxx_xxx_0

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

单片机I O口模拟串口 程序发送接收 Corporation standardization office #QS8QHH-HHGX8Q8-GNHHJ8

/*************************************************************** * 在单片机上模拟了一个串口,使用P2.1作为发送端 * 把单片机中存放的数据通过P2.1作为串口TXD发送出去 ***************************************************************/ #include #include #include typedef unsigned char uchar; int i; uchar code info[] = {

0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55 }; sbit newTXD = P2^1;//模拟串口的发送端设为P2.1 void UartInit() { SCON = 0x50; // SCON: serail mode 1, 8-bit UART TMOD |= 0x21; // T0工作在方式1,十六位定时 PCON |= 0x80; // SMOD=1; TH0 = 0xFE; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=11.0592MHz TL0 = 0x7F; // 定时器0初始值,延时417us,目的是令模拟串口的波特率为2400bps fosc=11.0592MHz

单片机IO口模拟RS232串口C语言程序

单片机I/O口模拟RS232串口C语言程序 #include sbit BT_SND =P1^0; sbit BT_REC =P1^1; /********************************************** IO 口模拟232通讯程序 使用两种方式的C程序占用定时器0 **********************************************/ #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; sbit ACC3= ACC^3; sbit ACC4= ACC^4; sbit ACC5= ACC^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; while(!F_TM); BT_SND=1; F_TM=0; while(!F_TM); TIMER0_DISABLE; //停止timer #else unsigned char ii; ii=0; F_TM=0;

51单片机软件用定时器模拟串口程序

51单片机软件用定时器模拟串口程序 模拟串口用定时器完成,每一个串口要占用一个定时器,发送很好办,每次定时器中断(1BIT的时间)传送一个Bit,接收就要你好好处理了,这个我模拟的一个串口,用的W77E58,实际工作时只用到了半双工。 //使用硬件:定时器0,定时器0中断,定时器1中断,外中断5 //波特率 9600 4800 2400 1200 600 300 //每BIT周期数 96 96*2 96*4 96*8 96*16 96*32 //以96为单位不同的波特率选用不同的倍率 //如果对方在每位的1/2处采样,则发送中断的响应时间最多是48个时钟周期 //也许可以置发送中断以较高的优先级来解决,实验表明发送可以工作于9600 //但若有其它中断,并且串口工作于全双工,则晶体频率最好是22.1184以上 //!!实测表明当用11.0592时钟,标准51,收发同时,最高只能到2400波特。

//但单发可以工作于9600 #define BAUD_RATE 300 //#define BAUD_RATE 600 //#define BAUD_RATE 1200 //#define BAUD_RATE 2400 //#define BAUD_RATE 4800 //#define BAUD_RATE 9600 #define clock 110592 //#define

clock 221184 #define RELOAD(TIMER,SVALUE) TIMER+=SVALUE+1 bit tTI; bit rRI; unsigned char rSBUF; unsigned char tSBUF; unsigned char rSBUF0; unsigned char RxdCnt; unsigned char rSmpCnt; unsigned char TxdCnt; unsigned char tSmpCnt; unsigned char multiple; //----------------------------------------------------------- void SimuUARTinit(void) { #if

串口模拟

随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。这种情况下下,采集会需要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的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 char sbit 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)

用AVR单片机模拟的串口程序.

用AVR单片机模拟的串口程序 用AVR单片机模拟的串口程序 类别:单片机/DSP 在一些应用中,经常要用到双串口,但是一般单片机只提供一个串口,其实完全可以用普通I/O口模拟一个串口。以下的程序是我编写的模拟串口程序,程序中使用了单片机的定时器0,和INT0中断。数据的发送和接收由中断程序自动进行。程序已经过AVR仿真器仿真和实际烧片使用,证明可靠。有一点需要说明的是,此模拟的串口为半双工方式。主程序中,单片机将标准串口设置为115200bps,将模拟串口设置为19200bps。单片机将标准串口收到的数据从模拟串口发送出去,将模拟串口接收到的数据从标准串口发送回来。 txd0_data: ldi status,(1< push temp in temp,gimsk cbr temp,(1< out gimsk,temp ;disable gimsk/int0 pop temp ser bit_cnt ;bit_cnt=0xff mov sbuf0,temp ;send data ldi temp,(256-N) out TCNT0,temp ;wait 1 bit timer0 interrupt in temp,tifr sbr temp,(1< out tifr,temp ;clr tifr/tov0 in temp,timsk sbr temp,(1< out timsk,temp ;enable timsk/toie0 cbi portb,txd0 ;uart start ret ; rxd0_data: sbrs status,fe0 ;if fe0=0 then exit rjmp rxd0_data_end cbr status,(1< mov temp,sbuf0 rxd0_data_end: ret ; ;uart received a byts from uart and then return it from uart0: ;uart received a byts from uart0 and then return it from uart : main: sbic usr,rxc rjmp send_115200 sbrs status,rdr rjmp uart_end send_19200: rcall rxd0_data ;get uart data from 19200bps uart0 wait2: sbis usr,udrie rjmp wait2 out udr,temp ;send data to 115200bps uart rjmp uart_end send_115200: in temp,udr ;get uart data from 115200bps uart sbic usr,fe rjmp uart_end ;if fe err then end wait3: sbrc status,td ;wait send flag rjmp wait3 rcall txd0_data ;send data to 19200bps uart0 uart_end: rjmp main

相关主题
文本预览
相关文档 最新文档