原创 Atmega32与PC机通讯模块

2011-8-1 19:44 2816 8 8 分类: 工业电子

上位机程序图:


点击看大图


/*
 * File: RF.C
 * use: 圆梦小车无线通讯模块
 *      主要实现小车与PC机软件的通信交流.
 *      同时也期望可为处理小车之间的通信创建必要的条件
 * Main point:
 *      实现数据的可靠传输,即主、从机可检测数据传输中的错误,并尝试恢复
 *      实现基本的多机通信机制,单主机、多从机
 *      设计有效的通信协议,基本的协议分层,使代码易于移植
 * By: lstzixing
 * Date: 2009-6-1
 */


#include <inttypes.h>
#include "app.h"


#define RF_MASTER_ADDR          0x0                        /* 主结点地址 ` */
#define RF_BROADCAST_ADDR       0xff                       /* 广播地址     */
#define RF_LOCALHOST_ADDR       0x1                        /* 本机地址     */
#define RF_PREAMBLE             0x53                       /* RF帧前导码   */
#define RF_FRAME_HDR_LEN        8                          /* RF帧头部长度 */
#define RF_FRAME_DATA_LEN       20                         /* RF数据域限长 */
#define RF_FRAME_MAX_LEN    ( RF_FRAME_HDR_LEN + RF_FRAME_DATA_LEN )


#define RF_CFLAG_NAK            0x0                        /* RF控制帧标志 NAK */


#define RF_TASK_PRIO            0x3                        /* RF任务的优先级 */
#define RF_TASK_STK_LEN         100                        /* RF任务的堆栈深度 */
#define RF_SLAVENODE_TIMEOUT    0x2                        /* 从结点等待数据帧超时量,以OS的时钟为基准 */


typedef struct                                             /* 通信帧       */
{
    INT8U preamble;                                      /* 通信帧前导码 */
    INT8U len;                                           /* 帧长度       */
    INT8U src;                                           /* 源结点地址   */
    INT8U dest;                                          /* 目的结点地址 */
    INT8U seq;                                           /* 序列号       */
    INT8U cflag;                                         /* 命令字       */
    INT16U crc;                                          /* CRC校验域    */
    INT8U data[RF_FRAME_DATA_LEN];                       /* 有效数据域   */
}RFFrame;


typedef BOOLEAN ( * CMDFun )( void * pdata, INT8U * len );


/* --------------------------------------------------------- */
OS_STK  RFTaskStk[ RF_TASK_STK_LEN ];                      /* RF任务堆栈区 */
static RFFrame rxFrame;                                    /* 帧缓冲区     */
static RFFrame txFrame;
static INT8U recvError;
static OS_EVENT * rxSem, * txSem;                          /* 驱动层与应用层同步信号量 */  


/* --------------------------------------------------------- */
static void   RFSlaveNodeTask( void * pdata );
static void RFLowLevelInit( void );
static void RFLowLevelOutput( void );
void RFLowLevelInput( void );
void RFLowLeveOutputIsr( void );


/* ----------------------RF命令支持 --------------------- */
#define RF_CFLAG_READ_MEM       0x1                        /* 请求读内存码 */
#define RF_CFLAG_WRITE_MEM      0x2                        /* 请求写内存码 */
#define RF_CFLAG_LED_FLASH       0x3                       /* 请求闪烁LED码*/


static BOOLEAN LEDFlash( void * pdata, INT8U * len );      /* RF_CFLAG_LED_FLASH支持 */


#define CMD_TBL_ENTRY_NR    ( sizeof(CMDTbl) / sizeof( CMDFun ) )
const  CMDFun   CMDTbl[] = {                                /* RF命令表 */
        ( CMDFun )0, ( CMDFun )0, ( CMDFun )0,
        LEDFlash
    };



/* ---------------------- RF初始化 --------------------------*/
void RFInit( void )
{
    recvError = 0;
    rxSem = OSSemCreate(0);
    txSem = OSSemCreate(1);
    OSTaskCreate( RFSlaveNodeTask, ( void * )0, &RFTaskStk[ RF_TASK_STK_LEN - 1 ], RF_TASK_PRIO );
    RFLowLevelInit();
}


/* --------------------- 创建数据帧 --------------------- */
static RFFrame * RFMakeFrame( RFFrame * frame, INT8U dest, INT8U seq, INT8U len, INT8U cflag )
{
    if( frame != ( void * )0 )
    {
        frame->preamble = RF_PREAMBLE;
        frame->src = RF_LOCALHOST_ADDR;
        frame->dest = dest;
        frame->len = len + RF_FRAME_HDR_LEN;
        frame->seq = seq;
        frame->cflag = cflag;
    }


    return  frame;
}


/* --------------------- RF从结点任务 --------------------- */
static void RFSlaveNodeTask( void * pdata )
{
        INT8U err;
        INT8U len;
        static INT8U lastSeq = 0;
        static BOOLEAN firstRecv = TRUE;


        pdata = pdata;
        while(1)
        {  
                /* 等待底层数据帧到达 */
                OSSemPend( rxSem, RF_SLAVENODE_TIMEOUT, &err );    
                if( err == OS_TIMEOUT )
                {
                    firstRecv = TRUE;
                }
                else if( rxFrame.dest == RF_LOCALHOST_ADDR )
                {
                    /* 仅处理往本机的帧 */
                    if( firstRecv )
                    {
                        /* 首次接收到新帧,刷新帧序列号 */
                        firstRecv = FALSE;
                        lastSeq = rxFrame.seq - 1;
                    }


                    if( recvError == FALSE )       
                    {
                        /* 帧在传输过程中未发生错误 */
                        if( rxFrame.seq != lastSeq )
                        {
                            /* 如果收到的帧是新的请求, 处理并响应 */
                            lastSeq = rxFrame.seq;


                            if( rxFrame.cflag < CMD_TBL_ENTRY_NR )
                            {
                                 if( ( *( CMDTbl + rxFrame.cflag) )( txFrame.data, &len ) )
                                      RFMakeFrame( &txFrame, rxFrame.src, lastSeq, len, rxFrame.cflag & 0x80 );
                                 else
                                      RFMakeFrame( &txFrame, rxFrame.src, lastSeq + 1, len, rxFrame.cflag );


                                 RFLowLevelOutput( );
                            }
                        }
                        else
                        {
                            /* 重复帧,丢弃,重发帧 */
                            RFLowLevelOutput( );
                        }
                    }          
                    else
                    {
                        /* 传输错误,发送NAK响应 */
                        RFMakeFrame( &txFrame, rxFrame.src, 0, 0, RF_CFLAG_NAK );
                        RFLowLevelOutput( );
                    }
                }          
        }
}


/* ---------------------- RF底层初始化 ----------------- */
static void RFLowLevelInit( void )
{
    /* RF底层硬件初始化,移植部分!!! */
    UCSRB = 1<<RXCIE | 1<<TXCIE | 1<<RXEN | 1<<TXEN;                   // 收发使能,接收中断
    UCSRC = 1<<URSEL| 1<<UPM1| 1<<UPM0| 1<<UCSZ1| 1<<UCSZ0;            // 异步,8位字节,奇校验
    UBRRL = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) & 0xff;     // 设置波特率
    UBRRH = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) >> 8;
}


/* ---------------------- RF底层数据发送处理 ----------------- */
static void RFLowLevelOutput( void )
{
    static INT8U * data = (INT8U *)&txFrame;
    static INT8U RFLowLevelOutputIndex = 0;
    INT8U err;


    while( RFLowLevelOutputIndex < txFrame.len )
    {
        /* 将DATA送至硬件端口,移植部分!!! */
        UDR = data[ RFLowLevelOutputIndex++ ];
        OSSemPend( txSem, 0, &err );
    }


    /* 发送完毕后关闭发送 */
    RFLowLevelOutputIndex = 0;
}


/* ---------------------- RF底层数据发送中断处理 ----------------- */
void RFLowLeveOutputIsr( void )
{
     /* 向调用RFLowLevelOutput的任务发信号,
      * 指示发送完成.必须在中断中调用! */
     OSSemPost( txSem );
}


/* ---------------------- RF底层数据接收处理 ----------------- */
void RFLowLevelInput( void )
{
    static INT8U len;
    static INT8U RFLowLevelInputIndex = 0;
    INT8U * ptr;
    INT8U data;


    /* 从实际链路读取数据,移植部分!!! */
    data = UDR;            
    ptr = (INT8U *)&rxFrame;
    if( data == RF_PREAMBLE && RFLowLevelInputIndex == 0 )
    {
        /* 数据为前导码,且写索引为0, 指示新帧开始 */
        ptr[ RFLowLevelInputIndex++ ] = data;
    }
    else
    {
        if( RFLowLevelInputIndex == 1 )               
        {        
            /* 获取数据帧长 */
            len = data > RF_FRAME_MAX_LEN ? RF_FRAME_MAX_LEN : data;
        }
           
        ptr[ RFLowLevelInputIndex++ ] = data;
        if( RFLowLevelInputIndex >= len )
        {
            /* 接收完毕,重置索引 */
            RFLowLevelInputIndex = 0;
            OSSemPost( rxSem );
        }
    }
}


/* ---------------------- RF_CFLAG_LED_FLASH 命令支持 ---------------- */
static BOOLEAN LEDFlash( void * pdata, INT8U * len )       
{
     *len = 0;
     LEDToggle( LED1 );
     return FALSE;
}

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /3 下一条