📄 mega16软件模拟2个串口程序.c
字号:
/*****************************软件模拟串口调试程序*****************************/
//编译环境ICCAVR ,MCU:MEGA16@8MHZ
//232端口:PD0--RXD PD1--TXD 485端口:PD2--RXD PD3--TXD
//模拟串口实现的方法:
//方法1、使用外部中断接收+函数发送/定时发送。这个方法适合高波特率通信。
//方法2、使用定时器定时查询。适合较低的波特率通信,容易实现全双工通信。
//
//以下是用方法2实现的,要非常注意的地方是:
//1、优先级控制宏,实现串口模拟定时器中断优先级最高,
// 防止定时漂移,实现100%正确率。
//2、定时器的精确定时,防止采样漂移。TIME2中断TCNT2的取值范围为:0xd0--0xd4;
//3、使用宏方便移植
//
//修改:李科 2006/08/12
//Target : M16
//Crystal: 8.0000Mhz 波特率:2400BIT/S
#include<iom16v.h>
#include<macros.h>
#define U8 unsigned char //宏定义char型变量
#define bool unsigned char //宏定义bool型变量
#define U16 unsigned int //宏定义int型变量
/*+++++++++++++++++++++++++++++++++=宏定义=+++++++++++++++++++++++++++++++++++*/
/* 宏中断优先级的使用:
1、要保存你所使用到的所有中断的使能位,然后关闭它们,仅开模拟串口定时器中断。
恢复时,只需恢复所有中断的使能位即可。
2、进入其它除了模拟串口定时器中断时,
先调用 IRQ_IP_OPEN() ;然后是你在该中断处理的代码 ,
退出该中断是调用 IRQ_IP_CLOSE() ;然后退出该中断。 */
// 中断优先级控制中要保持的变量(volatile表示之后程序中对此变量的赋值肯定执行)
volatile U8 saveUCSRB; // 串口中断
volatile U8 saveGICR; // 外部中断
volatile U8 saveTIMSK; // 定时器中断
// 中断优先级开启宏定义 屏蔽其它非高优先级中断 屏蔽INT0-2中断 屏蔽UART0中断 */
#define IRQ_IP_OPEN() {saveGICR=GICR;saveTIMSK=TIMSK;saveUCSRB=UCSRB;GICR=0x00;TIMSK=0x40;UCSRB&=0x1F;SEI();}
//屏蔽TIME0-1中断只开TIMER2中断模拟串口
// 中断优先级恢复宏定义 恢复其它非高优先级中断 恢复UART0接收、空中断
#define IRQ_IP_CLOSE() {CLI();GICR=saveGICR;TIMSK=saveTIMSK;UCSRB=saveUCSRB;}
//恢复INT0.2中断 恢复TIMER0.2中断
//管脚宏定义
#define GET_VM232_RX() (PIND & (1<<PD0)) //端口D的PD0模拟接收 读PD0值
#define SET_VM232_TX() {PORTD |= (1<<PD1);} //端口D的PD1发送1
#define CLR_VM232_TX() {PORTD &= ~(1<<PD1);} //端口D的PD1发送0
#define GET_VM485_RX() (PIND & (1<<PD2)) //端口D的PD2模拟接收 读PD2值
#define SET_VM485_TX() {PORTD |= (1<<PD3);} //端口D的PD3发送1
#define CLR_VM485_TX() {PORTD &= ~(1<<PD3);} //端口D的PD3发送0
/*++++++++++++++++++++++=系统52US定时器,用于模拟2个串口=+++++++++++++++++++++*/
/* 模拟串口的状态码;enum表示枚举:枚举是一个被命名的整型常数的集合
枚举是一个被命名的整型常数的集合, 枚举在日常生活中很常见。
例如表示星期的SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
就是一个枚举。 枚举的说明与结构和联合相似,
其形式为: enum 枚举名{ 标识符[=整型常数], 标识符[=整型常数], ...} 枚举变量;
如果枚举没有初始化, 即省掉"=整型常数"时, 则从第一个标识符开始,
顺次赋给标识符0, 1, 2, ...。但当枚举中的某个成员赋值后,
其后的成员按依次 加1的规则确定其值。 例如下列枚举说明后,
x1, x2, x3, x4的值分别为0, 1, 2, 3。 enum string{x1, x2, x3, x4}x;
当定义改变成: enum string { x1, x2=0, x3=50, x4, }x; 则x1=0, x2=0, x3=50, x4=51
注意: 1. 枚举中每个成员(标识符)结束符是",", 不是";", 最后一个成员可省略 ","。
2. 初始化时可以赋负数, 以后的标识符仍依次加1。
3. 枚举变量只能取枚举说明结构中的某个标识符常量。
例如: enum string {x1=5,x2,x3,x4,}; enum strig x=x3; 此时,枚举变量x实际上是7 */
enum {START,SDATA,STOP};
U8 inRS232 = 0; //模拟232的数据接收输入指针
U8 outRS232 = 0; //模拟232的数据接收取出指针
U8 vmRS232Buf[20];//模拟232的数据接收缓冲区
U8 inRS485 = 0; //模拟485的数据接收输入指针
U8 outRS485 = 0; //模拟485的数据接收取出指针
U8 vmRS485Buf[20];//模拟485的数据接收缓冲区
void vm_rs232_rx(U8 dataBit) // 模拟232接收函数
{
static U8 status = START;//static为本地全局变量
static U8 cnt = 0;
static U8 number = 0;
static U8 rData;
switch(status)
{
case START:
if(dataBit)
{
cnt = 0;
}
else
{
if(++cnt > 2)
{
cnt = 0;
number = 0;
status = SDATA;
}
}
break;
case SDATA:
if(++cnt > 3)
{
cnt = 0;
if(dataBit)
{
rData |= 0x80;
}
else
{
rData &= 0x7F;
}
if(++number < 8)
{
rData >>= 1;
}
else
{
number = 0;
status = STOP;
}
}
break;
case STOP:
if(++cnt > 3)
{
cnt = 0;
if(dataBit)
{
vmRS232Buf[inRS232++] = rData;
if(inRS232 >= 20) // 环型缓冲区
{
inRS232 = 0;
}
// 在这模拟的接收中断,不太实用
}
status = START;
}
break;
default:
cnt = 0;
status = START;
break;
}
}
void vm_rs485_rx(U8 dataBit) // 模拟485接收函数
{
static U8 status = START;
static U8 cnt = 0;
static U8 number = 0;
static U8 rData;
switch(status)
{
case START:
if(dataBit)
{
cnt = 0;
}
else
{
if(++cnt > 2)
{
cnt = 0;
number = 0;
status = SDATA;
}
}
break;
case SDATA:
if(++cnt > 3)
{
cnt = 0;
if(dataBit)
{
rData |= 0x80;
}
else
{
rData &= 0x7F;
}
if(++number < 8)
{
rData >>= 1;
}
else
{
number = 0;
status = STOP;
}
}
break;
case STOP:
if(++cnt > 3)
{
cnt = 0;
if(dataBit)
{
vmRS485Buf[inRS485++] = rData;
if(inRS485 >= 20) // 环型缓冲区
{
inRS485 = 0;
}
// 在这模拟的接收中断,不太实用
}
status = START;
}
break;
default:
cnt = 0;
status = START;
break;
}
}
bool flgVmRs232tx = 0; //模拟232是否有数据要发送的标志,1有数据要发送,完成清零
U8 vmRS232SBUF; //模拟232要发送的一字节缓冲
bool flgVmRs485tx = 0; //模拟485是否有数据要发送的标志,1有数据要发送,完成清零
U8 vmRS485SBUF; //模拟485要发送的一字节缓冲
void vm_rs232_tx(void) //模拟232发送函数
{
static U8 status = START;
static U8 cnt = 0;
static U8 number = 0;
if(flgVmRs232tx)
{
switch(status)
{
case START:
CLR_VM232_TX();
if(++cnt > 3)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -