串口通信框架

好久没更新技术博客了,前段时间看了MODBUS,写了一份主从机通信框架分享给大家


#include "comm.h"

#define COM_BUF_SIZE               30
#define COM_ADDR_BASE              0xA0 //slave address
#define COM_FRAME_SIZE_MIN         (6-2*COM_SOH_EOT)
#define COM_FRAME_ADDR_OFF         (COM_SOH_EOT+0)
#define COM_FRAME_FUNC_OFF         (COM_SOH_EOT+1)
#define COM_FRAME_LEN_OFF          (COM_SOH_EOT+2)
#define COM_FRAME_DATA_OFF         (COM_SOH_EOT+3)
#define COM_FRAME_START            0xFE
#define COM_FRAME_END              0xFF
#define COM_FUNC_ERROR             0x80
#define COM_FUNC_RESP              0x40

typedef enum
{
	STATE_RX_IDLE = 0,
	STATE_RX_RCV
} COM_RECV_STATE;

typedef enum
{
	STATE_TX_IDLE = 0,
	STATE_TX_XMIT
} COM_SEND_STATE;

typedef struct
{
    COM_SEND_STATE send_state;
    COM_RECV_STATE recv_state;

    U8 com_recv_buf[COM_BUF_SIZE];
    U8 com_send_buf[COM_BUF_SIZE];

    U8 recv_buf_pos;
    U8 recv_buf_len;

    U8 send_buf_pos;
    U8 send_buf_len;
}_COMM_DATA;


#if (COM_MASTER_MODE == 1)
volatile U8 master_user_send_data[2][COM_USER_BUF_SIZE];
volatile U8 master_user_recv_data[2][COM_USER_BUF_SIZE];
#else
volatile U8 slave_user_send_data[COM_USER_BUF_SIZE];
volatile U8 slave_user_recv_data[COM_USER_BUF_SIZE];
#endif

static EVENT_TYPE event = EV_NONE, curr_event = EV_NONE;
static U8 event_in_queue = FALSE;
static U32 com_tout_cnt = 0, req_tout_cnt = 0, req_handing = 1;
static volatile U8 slave_address = 0xA0;

static volatile _COMM_DATA comm_data;

static void rx_tx_enable(U8 rx_en, U8 tx_en);
static void uart_get_byte(U8 *c);
static void uart_put_byte(U8 c);
static void uart_init(U32 baud);
static void com_tout35_irq(void);

static COM_ERRNO slave_broadcast(U8 *recv_buf, U8 recv_len, U8 **send_buf, U8 *send_len);
static COM_ERRNO slave_func_01(U8 *recv_buf, U8 recv_len, U8 **send_buf, U8 *send_len);

static COM_ERRNO master_broadcast(U8 saddr, U8 *recv_buf, U8 recv_len);
static COM_ERRNO master_func_01(U8 saddr, U8 *recv_buf, U8 recv_len);
__interrupt void SCIATx_ISR(void);
__interrupt void SCIARx_ISR(void);

#if (COM_MASTER_MODE == 1)
#define MB_FUNC_HANDLERS_MAX    1
static FUNC_MASTER xfunc_master[MB_FUNC_HANDLERS_MAX] =
{
	{0x01, master_func_01}
};
#else
#define MB_FUNC_HANDLERS_MAX    1
static FUNC_SLAVE xfunc_slave[MB_FUNC_HANDLERS_MAX] =
{
	{0x01, slave_func_01}
};
#endif

U16 com_checksum(U8 data[], U16 len)
{
    U16 sum = 0, i;
    
    for(i = 0; i < len; i++)
    {
        sum += data[i];
    }

    sum = ~sum;

    sum &= 0xFF;

    return sum;
}

void * mem_move(void * dest, const void *src, U16 count)
{
	U8 *tmp, *s;

	if (src == dest)
		return dest;

	if (dest <= src) 
    {
		tmp = (U8 *) dest;
		s = (U8 *) src;
		while (count--)
			*tmp++ = *s++;
    }
	else 
    {
		tmp = (U8 *) dest + count;
		s = (U8 *) src + count;
		while (count--)
			*--tmp = *--s;
    }

	return dest;
}

void event_init(void)
{
	event = EV_NONE;
}

U8 post_event(EVENT_TYPE ev)
{
	event = ev;
    
	return TRUE;
}

U8 get_event(EVENT_TYPE *ev)
{
    if(event != EV_NONE)
    {
        *ev = event;
        curr_event = event;
        event = EV_NONE;
        
        return TRUE;
    }

    return FALSE;
}

U8 get_curr_event(EVENT_TYPE *ev)
{
    *ev = curr_event;

    return TRUE;
}

COM_ERRNO com_frame_recv(U8 *recv_addr, U8 *func_code, U8 **recv_data, U8 *recv_len)
{
	COM_ERRNO status = E_NONE;

	if((comm_data.recv_buf_len >= COM_FRAME_SIZE_MIN))
    //&& com_checksum(comm_data.com_recv_buf, comm_data.recv_buf_len) == ((0xFF+COM_SOH_EOT*COM_FRAME_END)&0xFF))
	{
		*recv_addr = comm_data.com_recv_buf[COM_FRAME_ADDR_OFF];
        *func_code = comm_data.com_recv_buf[COM_FRAME_FUNC_OFF];
		*recv_len = comm_data.com_recv_buf[COM_FRAME_LEN_OFF];
		*recv_data = (U8 *) &comm_data.com_recv_buf[COM_FRAME_DATA_OFF];
	}
	else
	{
		status = E_BADVAL;
	}

	return status;
}

COM_ERRNO com_frame_send(U8 send_addr, U8 func_code, const U8* send_data, U8 send_len)
{
	COM_ERRNO status = E_NONE;
	U8 i, chksum = 0;

    if(send_len == 0)
    {
        rx_tx_enable(TRUE, FALSE);
        return status;
    }

	if(comm_data.recv_state == STATE_RX_IDLE)
	{
		comm_data.send_buf_len = 0;
     #if (COM_SOH_EOT == 1)
        comm_data.com_send_buf[comm_data.send_buf_len++] = COM_FRAME_START;
     #else
     
     #endif
		comm_data.com_send_buf[comm_data.send_buf_len++] = send_addr;
		comm_data.com_send_buf[comm_data.send_buf_len++] = func_code;
		comm_data.com_send_buf[comm_data.send_buf_len++] = send_len;
		for(i = 0; i < send_len; i++)
		{
			comm_data.com_send_buf[comm_data.send_buf_len++] = send_data[i];
		}
        chksum = com_checksum(comm_data.com_send_buf, comm_data.send_buf_len);
		comm_data.com_send_buf[comm_data.send_buf_len++] = chksum;
     #if (COM_SOH_EOT == 1)
		comm_data.com_send_buf[comm_data.send_buf_len++] = (U8)COM_FRAME_END;
     #else
     #endif

        comm_data.send_buf_pos = 0;
		comm_data.send_state = STATE_TX_XMIT;
		rx_tx_enable(FALSE, TRUE);
        
        uart_put_byte(comm_data.com_send_buf[comm_data.send_buf_pos++]);
        com_tout_cnt = 1;
	}
	else
	{
		status = E_BADVAL;
	}

	return status;
}

void com_recv_irq(void)
{
	U8 byte = 0xCC, i, cnt;

	if(comm_data.send_state != STATE_TX_IDLE) return;

	uart_get_byte(&byte);
    //dbg_recv_data[dbg_recv_point++] = byte;
    
	if(comm_data.recv_state == STATE_RX_IDLE)
	{
    	comm_data.recv_buf_len = 0;
    #if (COM_SOH_EOT == 1)
    	if(byte == COM_FRAME_START)
    #else
        if((byte & COM_ADDR_BASE) == COM_ADDR_BASE)
    #endif
    	{
    		comm_data.com_recv_buf[comm_data.recv_buf_len++] = byte;
    		comm_data.recv_state = STATE_RX_RCV;
    	}
    	com_tout_cnt = 1;
	}
	else if(comm_data.recv_state == STATE_RX_RCV)
	{
        com_tout_cnt = 1;
        comm_data.com_recv_buf[comm_data.recv_buf_len++] = byte;
		if(comm_data.recv_buf_len < COM_BUF_SIZE)
		{
        #if (COM_SOH_EOT == 1)
            if(comm_data.recv_buf_len < COM_FRAME_SIZE_MIN)
            {
                switch(comm_data.recv_buf_len-1)
                {
                    case COM_FRAME_ADDR_OFF:
                        if((byte & COM_ADDR_BASE) != COM_ADDR_BASE)
                        {
                            comm_data.recv_state = STATE_RX_IDLE;
                        }
                        break;
                    case COM_FRAME_FUNC_OFF:
                        break;
                    case COM_FRAME_LEN_OFF:
                        if(byte > COM_BUF_SIZE)
                        {
                            comm_data.recv_state = STATE_RX_IDLE;
                        }
                        break;
                    default:
                        break;          
                }
            }
            else if(comm_data.com_recv_buf[COM_FRAME_LEN_OFF]+6 == comm_data.recv_buf_len)
			{
				if(byte == COM_FRAME_END)
				{
                    rx_tx_enable(FALSE, FALSE);
					//post_event(EV_FRAME_RECV);
			    #if (COM_MASTER_MODE == 1)
        			post_event(EV_FRAME_RECV);
                #else
                    post_event(EV_FRAME_RECV);
                #endif
					comm_data.recv_state = STATE_RX_IDLE;
                    com_tout_cnt = 0;
				}
				else
				{
                    for(i = 1, cnt = comm_data.recv_buf_len; i < cnt; i++)
                    {
                        if(comm_data.com_recv_buf[i] == COM_FRAME_START)
                        {
                            mem_move((U8 *)&comm_data.com_recv_buf[0], (U8 *)&comm_data.com_recv_buf[i], comm_data.recv_buf_len-i);
                            comm_data.recv_buf_pos = i;
                            comm_data.recv_buf_len -= i;
                            break;
                        }
                    }
                    if(i >= cnt)
                    {
                        comm_data.recv_state = STATE_RX_IDLE; 
                    }
				}
			}
        #else
            
        #endif
		}
		else
		{
			comm_data.recv_state = STATE_RX_IDLE;
		}
	}
    else
    {
        comm_data.recv_state = STATE_RX_IDLE;
    }
}

void com_send_irq(void)
{
	if(comm_data.recv_state != STATE_RX_IDLE) return;

	if(comm_data.send_state == STATE_TX_IDLE)
	{
		rx_tx_enable(TRUE, FALSE);
	}
	else if(comm_data.send_state == STATE_TX_XMIT)
	{
        com_tout_cnt = 1;
		if(comm_data.send_buf_pos < comm_data.send_buf_len)
		{
			uart_put_byte(comm_data.com_send_buf[comm_data.send_buf_pos++]);
		}
		else
		{
        #if (COM_MASTER_MODE == 1)
        
        #else
            post_event(EV_FRAME_SENT);
        #endif
            com_tout_cnt = 0;
			comm_data.send_state = STATE_TX_IDLE;
            rx_tx_enable(TRUE, FALSE);
		}
	}
}

void com_tout35_irq(void)
{
	com_tout_cnt = 0;
    if(comm_data.recv_state != STATE_RX_IDLE)
    {
    #if (COM_SOH_EOT == 1)

    #else
        rx_tx_enable(FALSE, FALSE);
        post_event(EV_FRAME_RECV);
    #endif
        comm_data.recv_state = STATE_RX_IDLE;
    }
    if(comm_data.send_state != STATE_TX_IDLE)
    {
        //post_event(EV_FRAME_RECV);
        comm_data.send_state = STATE_TX_IDLE;
        rx_tx_enable(TRUE, FALSE);
    }
}

void timer_expired_1ms(void)
{
	if(com_tout_cnt && com_tout_cnt < 0xFFFF)
	{
		com_tout_cnt++;
	}
    if(com_tout_cnt > 3)
    {
	    com_tout35_irq();
        com_tout_cnt = 0;
    }
 #if (COM_MASTER_MODE == 1)
    if(req_tout_cnt)
	{
		req_tout_cnt--;
	}
 #endif
}

COM_ERRNO com_init(U8 slave_addr, U32 baud_rate)
{
	COM_ERRNO status = E_NONE;
    U32 tout35_us = ~0;

	slave_address = slave_addr;
    uart_init(baud_rate);
	if(baud_rate >= 19200)
	{
		tout35_us = 1823;       /* 1823us. */
	}
	else
	{
		tout35_us = 35000000UL / baud_rate;
	}

	event_init();
    com_tout_cnt = 0;
    MemSet((U8 *)&comm_data, 0, sizeof(_COMM_DATA));
#if (COM_MASTER_MODE == 1)
    MemSet(master_user_send_data, 0, sizeof(master_user_send_data));
    MemSet(master_user_recv_data, 0, sizeof(master_user_recv_data));
    rx_tx_enable(FALSE, TRUE);
#else
    MemSet((U8 *)slave_user_send_data, 0, sizeof(slave_user_send_data));
    MemSet((U8 *)slave_user_recv_data, 0, sizeof(slave_user_recv_data));
    rx_tx_enable(TRUE, FALSE);
#endif

	return status;
}
#if (COM_MASTER_MODE == 0)
COM_ERRNO com_slave_poll(void)
{
	static U8 recv_addr, func_code = 0, recv_len = 0, send_len = 0, i;
    static U8 *recv_data;

    static U8 *send_data = NULL;
	static COM_ERRNO except_code;

	COM_ERRNO status = E_NONE;
	EVENT_TYPE ev;

	if(get_event(&ev) == TRUE)
	{
		switch(ev)
		{
			case EV_FRAME_RECV:
				status = com_frame_recv(&recv_addr, &func_code, &recv_data, &recv_len);

				if(status == E_NONE && (recv_addr == slave_address || recv_addr == COM_BOARDCAST_ADDR))
				{
					post_event(EV_EXEC_FUNC);
				}
                else
                {
                    rx_tx_enable(TRUE, FALSE);
                }
				break;
			case EV_EXEC_FUNC:
                
				except_code = E_BADRQC;

                if(recv_addr == COM_BOARDCAST_ADDR)
                {
                    except_code = slave_broadcast(recv_data, recv_len, &send_data, &send_len);
                }
                else
                {
    				for(i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
    				{
    					if(xfunc_slave[i].func_code == func_code)
    					{
    						except_code = xfunc_slave[i].pfun_callback(recv_data, recv_len, &send_data, &send_len);
    						break;
    					}
    				}
                }
                if(except_code)
                {
                    *send_data = except_code;
                    send_len = 1;
                    status = com_frame_send(slave_address, func_code|COM_FUNC_ERROR, send_data, send_len);
                }
                else
                {
                    status = com_frame_send(slave_address, func_code|COM_FUNC_RESP, send_data, send_len);
                }
				
				post_event(EV_FRAME_SENT);
				break;
			case EV_FRAME_SENT:
				break;
		}
	}

	return status;
}
//emergency situations such as shut down
COM_ERRNO slave_broadcast(U8 *recv_buf, U8 recv_len, U8 **send_buf, U8 *send_len)
{
    *send_len = 0; // no response expect
    
    return E_NONE;
}

COM_ERRNO slave_func_01(U8 *recv_buf, U8 recv_len, U8 **send_buf, U8 *send_len)
{
    MemCpy((U8 *)slave_user_recv_data, recv_buf, recv_len);
    *send_buf = (U8 *)slave_user_send_data;
    *send_len = sizeof(slave_user_send_data);
    
    return E_NONE;
}

#else
U8 get_request_result(COM_ERRNO *err)
{
    EVENT_TYPE ev;
    
    if(req_handing)
    {
        get_curr_event(&ev);
        if(ev == EV_EXEC_DONE)
        {
            *err = E_NONE;
            req_handing = 0;
            return TRUE;
        }
        else if(req_tout_cnt == 0)
        {
            *err = E_TOUT;
            req_handing = 0;
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    
    return FALSE;

}
COM_ERRNO master_request(U8 addr, U8 func, U8 *send_data, U8 send_len, U32 tout_ms)
{
	static COM_ERRNO status = E_NONE;

    req_tout_cnt = tout_ms;
    req_handing = 1;
    
    slave_address = addr;
    comm_data.recv_state = STATE_RX_IDLE;
	status = com_frame_send(addr, func, send_data, send_len);
    if(addr == COM_BOARDCAST_ADDR)
    {
        post_event(EV_EXEC_DONE);
    }
    else
    {
        post_event(EV_FRAME_SENT);
    }
    status = E_HANDLING;
    
	return status;
}

COM_ERRNO com_master_poll(void)
{
	static U8 recv_addr, func_code = 0, recv_len = 0, send_len = 0, i;
    static U8 *recv_data;

	static COM_ERRNO except_code;

	COM_ERRNO status = E_NONE;
	EVENT_TYPE ev;

	if(get_event(&ev) == TRUE)
	{
		switch(ev)
		{
			case EV_FRAME_RECV:
				status = com_frame_recv(&recv_addr, &func_code, &recv_data, &recv_len);

				if(status == E_NONE && (recv_addr == slave_address || recv_addr == COM_BOARDCAST_ADDR))
				{
					post_event(EV_EXEC_FUNC);
				}
                else
                {
                    rx_tx_enable(TRUE, FALSE);
                }
				break;
			case EV_EXEC_FUNC:
                
				except_code = E_BADRQC;

                if(recv_addr == COM_BOARDCAST_ADDR)
                {
                    //except_code = master_broadcast(slave_address, recv_data, recv_len);
                }
                else
                {
    				for(i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
    				{
    					if(xfunc_master[i].func_code == func_code)
    					{
    						except_code = xfunc_master[i].pfun_callback(slave_address, recv_data, recv_len);
    						break;
    					}
    				}
                }
				post_event(EV_EXEC_DONE);
				break;
			case EV_FRAME_SENT:
				break;
            case EV_EXEC_DONE:
                rx_tx_enable(TRUE, FALSE);
				break;
		}
	}

	return status;
}

COM_ERRNO master_func_01(U8 saddr, U8 *recv_buf, U8 recv_len)
{
    MemCpy(master_user_recv_data[saddr-COM_ADDR_BASE], recv_buf, recv_len);
    
    return E_NONE;
}

COM_ERRNO master_broadcast(U8 saddr, U8 *recv_buf, U8 recv_len)
{
    
    return E_NONE;
}

#endif
/******************porting*************************/
void rx_tx_enable(U8 rx_en, U8 tx_en)
{
    //EALLOW;
	if(rx_en)
	{
        SciaRegs.SCICTL2.bit.RXBKINTENA = 1;
	}
    else
    {
        SciaRegs.SCICTL2.bit.RXBKINTENA = 0;
    }

	if(tx_en)
	{
		SciaRegs.SCICTL2.bit.TXINTENA = 1;
	}
    else
    {
        SciaRegs.SCICTL2.bit.TXINTENA = 0;
    }

    NOP;
    NOP;
    NOP;
    //SciaRegs.SCICTL1.all = 0x23;
}

void uart_init(U32 baud)
{
    U32 brr_reg;

    brr_reg = ((15000000UL*10)/(baud*8)+5)/10-1;
    
    InitSciGpio();

    
}

void uart_put_byte(U8 c)
{
    SciaRegs.SCITXBUF = c;
}

void uart_get_byte(U8 *c)
{
    *c = SciaRegs.SCIRXBUF.all&0xFF;
}

__interrupt void SCIATx_ISR(void)
{
    DINT;
 	com_send_irq();
	
	SciaRegs.SCIFFTX.bit.TXFFINTCLR = 1;	// Clear SCI Interrupt flag
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;      // Issue PIE ACK
}

__interrupt void SCIARx_ISR(void)  //UART for debug
{
    com_recv_irq();

	SciaRegs.SCIFFRX.bit.RXFFOVRCLR = 1;   // Clear Overflow flag
	SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1;   // Clear Interrupt flag

	PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;    // Issue PIE ack
}
/********************example************************/
void comm_test_init(void)
{
    com_init(0xA0, 19200);
    set_timer(TMR_COMM_DBUG, 5000*MS_T);
    set_timer(TMR_COMM_1MS, 1*MS_T);
}

void comm_test(void)
{
    static COM_ERRNO err = E_NONE;
    const Uint16 send_array[] = {0x12, 0x34, 0x56, 0x78, 0x9A};
    
    ServiceDog();
    
#if (COM_MASTER_MODE == 1)
    com_master_poll();
    
    if(chk_timer(TMR_COMM_DBUG))
    {
        err = master_request(0xA0, 0x01, master_user_send_data[0], sizeof(send_array), 8000);
        set_timer(TMR_COMM_DBUG, 10000*MS_T);
    }
    
    if(get_request_result(&err))
    {
        if(err == E_NONE)
        {
           //uart_put_byte('#'); // success then send the next frame
           err = master_request(0xA0, 0x01, send_array, sizeof(send_array), 8000);
        }
        set_timer(TMR_COMM_DBUG, 10000*MS_T);
    }
#else
    com_slave_poll();
#endif
    if(chk_timer(TMR_COMM_1MS))
    {
        timer_expired_1ms();
        set_timer(TMR_COMM_1MS, 1*MS_T);
    }
}



#ifndef _COMM_H_
#define _COMM_H_

#define COM_BOARDCAST_ADDR       0xAF
#define COM_USER_BUF_SIZE        10
#define COM_MASTER_MODE          1 // 0:slave 1:master
#define COM_SOH_EOT              0 // 0:time delimiter 1:char delimiter


typedef unsigned int   U8;
typedef int            I8;
typedef unsigned int   U16;
typedef int            I16;
typedef unsigned long  U32;
typedef long           I32;

#ifndef TRUE
	#define TRUE                    1
#endif

#ifndef FALSE
	#define FALSE                   0
#endif

typedef enum
{
	E_NONE = 0x00,
	E_BADRQC,
	E_BADADDR,
	E_BADVAL,
	E_HANDLING,
	E_TOUT
} COM_ERRNO;

#if (COM_MASTER_MODE == 1)
typedef COM_ERRNO (*pfunc_master)(U8 saddr, U8 *recv_buf, U8 recv_len);

typedef struct
{
	U8 func_code;
	pfunc_master pfun_callback;
} FUNC_MASTER;
#else
typedef COM_ERRNO (*pfunc_slave)(U8* recv_buf, U8 recv_len, U8 **send_buf, U8 *send_len);

typedef struct
{
	U8 func_code;
	pfunc_slave pfun_callback;
} FUNC_SLAVE;
#endif

typedef enum
{
	EV_READY,
	EV_FRAME_RECV,
	EV_EXEC_FUNC,
	EV_FRAME_SENT,
	EV_EXEC_DONE,
	EV_NONE,
} EVENT_TYPE;

extern void comm_test_init(void);
extern void comm_test(void);
extern COM_ERRNO com_init(U8 slave_addr, U32 baud_rate);
extern COM_ERRNO com_slave_poll(void);
extern COM_ERRNO com_master_poll(void);
extern COM_ERRNO master_request(U8 addr, U8 func, U8 *send_data, U8 send_len, U32 tout_ms);

#endif



猜你喜欢

转载自blog.csdn.net/fz835304205/article/details/53844474