⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mega16软件模拟2个串口程序.c

📁 基于ICCAVR平台的
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************软件模拟串口调试程序*****************************/
//编译环境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 + -