?? mega16軟件模擬2個串口程序.c
字號:
/*****************************軟件模擬串口調(diào)試程序*****************************/
//編譯環(huán)境ICCAVR ,MCU:MEGA16@8MHZ
//232端口:PD0--RXD PD1--TXD 485端口:PD2--RXD PD3--TXD
//模擬串口實現(xiàn)的方法:
//方法1、使用外部中斷接收+函數(shù)發(fā)送/定時發(fā)送。這個方法適合高波特率通信。
//方法2、使用定時器定時查詢。適合較低的波特率通信,容易實現(xiàn)全雙工通信。
//
//以下是用方法2實現(xiàn)的,要非常注意的地方是:
//1、優(yōu)先級控制宏,實現(xiàn)串口模擬定時器中斷優(yōu)先級最高,
// 防止定時漂移,實現(xiàn)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型變量
/*+++++++++++++++++++++++++++++++++=宏定義=+++++++++++++++++++++++++++++++++++*/
/* 宏中斷優(yōu)先級的使用:
1、要保存你所使用到的所有中斷的使能位,然后關(guān)閉它們,僅開模擬串口定時器中斷。
恢復(fù)時,只需恢復(fù)所有中斷的使能位即可。
2、進(jìn)入其它除了模擬串口定時器中斷時,
先調(diào)用 IRQ_IP_OPEN() ;然后是你在該中斷處理的代碼 ,
退出該中斷是調(diào)用 IRQ_IP_CLOSE() ;然后退出該中斷。 */
// 中斷優(yōu)先級控制中要保持的變量(volatile表示之后程序中對此變量的賦值肯定執(zhí)行)
volatile U8 saveUCSRB; // 串口中斷
volatile U8 saveGICR; // 外部中斷
volatile U8 saveTIMSK; // 定時器中斷
// 中斷優(yōu)先級開啟宏定義 屏蔽其它非高優(yōu)先級中斷 屏蔽INT0-2中斷 屏蔽UART0中斷 */
#define IRQ_IP_OPEN() {saveGICR=GICR;saveTIMSK=TIMSK;saveUCSRB=UCSRB;GICR=0x00;TIMSK=0x40;UCSRB&=0x1F;SEI();}
//屏蔽TIME0-1中斷只開TIMER2中斷模擬串口
// 中斷優(yōu)先級恢復(fù)宏定義 恢復(fù)其它非高優(yōu)先級中斷 恢復(fù)UART0接收、空中斷
#define IRQ_IP_CLOSE() {CLI();GICR=saveGICR;TIMSK=saveTIMSK;UCSRB=saveUCSRB;}
//恢復(fù)INT0.2中斷 恢復(fù)TIMER0.2中斷
//管腳宏定義
#define GET_VM232_RX() (PIND & (1<<PD0)) //端口D的PD0模擬接收 讀PD0值
#define SET_VM232_TX() {PORTD |= (1<<PD1);} //端口D的PD1發(fā)送1
#define CLR_VM232_TX() {PORTD &= ~(1<<PD1);} //端口D的PD1發(fā)送0
#define GET_VM485_RX() (PIND & (1<<PD2)) //端口D的PD2模擬接收 讀PD2值
#define SET_VM485_TX() {PORTD |= (1<<PD3);} //端口D的PD3發(fā)送1
#define CLR_VM485_TX() {PORTD &= ~(1<<PD3);} //端口D的PD3發(fā)送0
/*++++++++++++++++++++++=系統(tǒng)52US定時器,用于模擬2個串口=+++++++++++++++++++++*/
/* 模擬串口的狀態(tài)碼;enum表示枚舉:枚舉是一個被命名的整型常數(shù)的集合
枚舉是一個被命名的整型常數(shù)的集合, 枚舉在日常生活中很常見。
例如表示星期的SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
就是一個枚舉。 枚舉的說明與結(jié)構(gòu)和聯(lián)合相似,
其形式為: enum 枚舉名{ 標(biāo)識符[=整型常數(shù)], 標(biāo)識符[=整型常數(shù)], ...} 枚舉變量;
如果枚舉沒有初始化, 即省掉"=整型常數(shù)"時, 則從第一個標(biāo)識符開始,
順次賦給標(biāo)識符0, 1, 2, ...。但當(dāng)枚舉中的某個成員賦值后,
其后的成員按依次 加1的規(guī)則確定其值。 例如下列枚舉說明后,
x1, x2, x3, x4的值分別為0, 1, 2, 3。 enum string{x1, x2, x3, x4}x;
當(dāng)定義改變成: enum string { x1, x2=0, x3=50, x4, }x; 則x1=0, x2=0, x3=50, x4=51
注意: 1. 枚舉中每個成員(標(biāo)識符)結(jié)束符是",", 不是";", 最后一個成員可省略 ","。
2. 初始化時可以賦負(fù)數(shù), 以后的標(biāo)識符仍依次加1。
3. 枚舉變量只能取枚舉說明結(jié)構(gòu)中的某個標(biāo)識符常量。
例如: enum string {x1=5,x2,x3,x4,}; enum strig x=x3; 此時,枚舉變量x實際上是7 */
enum {START,SDATA,STOP};
U8 inRS232 = 0; //模擬232的數(shù)據(jù)接收輸入指針
U8 outRS232 = 0; //模擬232的數(shù)據(jù)接收取出指針
U8 vmRS232Buf[20];//模擬232的數(shù)據(jù)接收緩沖區(qū)
U8 inRS485 = 0; //模擬485的數(shù)據(jù)接收輸入指針
U8 outRS485 = 0; //模擬485的數(shù)據(jù)接收取出指針
U8 vmRS485Buf[20];//模擬485的數(shù)據(jù)接收緩沖區(qū)
void vm_rs232_rx(U8 dataBit) // 模擬232接收函數(shù)
{
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) // 環(huán)型緩沖區(qū)
{
inRS232 = 0;
}
// 在這模擬的接收中斷,不太實用
}
status = START;
}
break;
default:
cnt = 0;
status = START;
break;
}
}
void vm_rs485_rx(U8 dataBit) // 模擬485接收函數(shù)
{
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) // 環(huán)型緩沖區(qū)
{
inRS485 = 0;
}
// 在這模擬的接收中斷,不太實用
}
status = START;
}
break;
default:
cnt = 0;
status = START;
break;
}
}
bool flgVmRs232tx = 0; //模擬232是否有數(shù)據(jù)要發(fā)送的標(biāo)志,1有數(shù)據(jù)要發(fā)送,完成清零
U8 vmRS232SBUF; //模擬232要發(fā)送的一字節(jié)緩沖
bool flgVmRs485tx = 0; //模擬485是否有數(shù)據(jù)要發(fā)送的標(biāo)志,1有數(shù)據(jù)要發(fā)送,完成清零
U8 vmRS485SBUF; //模擬485要發(fā)送的一字節(jié)緩沖
void vm_rs232_tx(void) //模擬232發(fā)送函數(shù)
{
static U8 status = START;
static U8 cnt = 0;
static U8 number = 0;
if(flgVmRs232tx)
{
switch(status)
{
case START:
CLR_VM232_TX();
if(++cnt > 3)
{
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -