|
从我的实际工程软件中删减而来,没有进行仔细的调试,自由使用但本人不提供任何担保。
或许对初学者有启发作用:)
/* Title: Interrupt driven serial example(RS-485). * Author: Daidai Hu * Date: 06/2003 * Purpose: Template for RS-485 slave communication program. * Needed * Software: AVR-GCC 3.3 to compile * Needed * Hardware: ATMega103 board with serial 0 connected to RS-485 bus. */
#include <stdlib.h> #include <inttypes.h> #include <string.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include <avr/pgmspace.h> #include <avr/eeprom.h>
#define F_CPU 6000000 /* 6MHz. */ #define MAX_RCV_LEN 128 /* Maximal receive message length. */ #define MAX_SND_LEN 128 /* Maximal send message length. */
#define UART_BAUD_SELECT(bps) (F_CPU/((bps)*16L)-1)
#define TICK 2 /* System tick(ms). */ #define SRL_TOUT 20 /* Idle time between serial frames(ms). */
/* D7-D2: Reserved(0). * D1-D0: Baud rate select, 0=19200, 1=9600..., 3=2400. */ uint8_t ucBaud_g;
/* Const table for baud rate register. */ prog_char aucBdTbl_c[]= { UART_BAUD_SELECT(19200), UART_BAUD_SELECT(9600), UART_BAUD_SELECT(4800), UART_BAUD_SELECT(2400), };
/* Global flag. */ volatile uint8_t ucFlag_g; #define RECV_ERR 0x01 #define RECV_FRM 0x02 #define SEND_MSG 0x04
#define RS485_TX_ON sbi(PORTC, 0) #define RS485_TX_OFF cbi(PORTC, 0)
/* Serial buffer. */ uint8_t aucRcvBuf_g[MAX_RCV_LEN], aucSndBuf_g[MAX_SND_LEN]; /* Receive length, send length and now send position. */ volatile uint8_t ucRcvLen_g, ucSndLen_g, ucSndPos_g; volatile uint8_t ucSrlTout_g; /* Frame time out counter. */
static void Deal_Recv_Msg(void);
int main(void) { volatile uint16_t unDelay;
/* Power on delay. */ for (ucBaud_g=0; ucBaud_g<10; ucBaud_g++) { for (unDelay=0; unDelay<60000; unDelay++) continue; }
/* Set timer 1 capture interrupt as system tick. */ TCCR1A=0x00; TCCR1B=0x09; OCR1AH=((F_CPU*TICK/1000) & 0xFF00)>>8; OCR1AL=(F_CPU*TICK/1000) & 0xFF; sbi(TIMSK, OCIE1A); /* Enable interrupt. */
ucBaud_g=eeprom_rb(0x10);
/* Default baud rate=9600. */ if (ucBaud_g>3) ucBaud_g=1; /* Set baud rate. */ UBRR=PRG_RDB(&aucBdTbl_c[ucBaud_g]); /* Enable RxD/TxD and ints. */ UCR=(1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
sei(); /* Enable interrupts. */
while (1) { if (ucFlag_g & RECV_FRM) { Deal_Recv_Msg(); cli(); ucRcvLen_g=0; ucFlag_g &= ~(RECV_FRM | RECV_ERR); sei(); } } }
/* Signal handler for receive complete interrupt. */ SIGNAL(SIG_UART_RECV) { uint8_t ucFromUart;
ucFromUart=UDR; /* Read the Rx data first. */ /* Check if last command not dealed over. */ if ((ucFlag_g & RECV_FRM) || ucRcvLen_g>=MAX_RCV_LEN) ucFlag_g |= RECV_ERR; else if (!(ucFlag_g & SEND_MSG)) aucRcvBuf_g[ucRcvLen_g++]=ucFromUart; ucFromUart=USR; if (ucFromUart & ((0x01<<FE) | (0x01<<DOR))) ucFlag_g |= RECV_ERR;
ucSrlTout_g=SRL_TOUT/TICK; /* Reset the timeout counter. */ }
/* Signal handler for uart data buffer empty interrupt. */ SIGNAL(SIG_UART_DATA) { /* Write byte to data buffer. */ UDR=aucSndBuf_g[ucSndPos_g++]; if (ucSndPos_g>=ucSndLen_g) /* If buffer is empty: */ { cbi(UCR, UDRIE); /* Disable UDRIE interrupt. */ sbi(UCR, TXCIE); } }
SIGNAL(SIG_UART_TRANS) { cbi(UCR, TXCIE); RS485_TX_OFF; ucFlag_g &= ~SEND_MSG; /* Last message was dealed. */ }
SIGNAL(SIG_OUTPUT_COMPARE1A) /* Timer 1 output compare. */ { if (ucSrlTout_g && !(--ucSrlTout_g)) ucFlag_g |= RECV_FRM; }
static void Deal_Recv_Msg(void) { /* TODO: deal with receive message here. */ if (ucFlag_g & RECV_ERR) return; memcpy(aucSndBuf_g, aucRcvBuf_g, ucRcvLen_g); ucSndLen_g=ucRcvLen_g;
if (ucSndLen_g>=5) { ucSndPos_g=0;
cli();
ucRcvLen_g=0;
ucFlag_g &= ~(RECV_FRM | RECV_ERR); ucFlag_g |= SEND_MSG;
RS485_TX_ON;
sbi(UCR, UDRIE);
sei(); } }
|