好久没更新技术博客了,前段时间看了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