/* Title: Interrupt driven serial example(RS-485).
* Author: Daidai Hu
* Date: 06/2003
* Purpose: Template for RS-485 slave communICation program.
* Needed
*SOFtware: AVR-GCC3.3 to compile
* Needed
* Hardware: ATMega103 board with serial 0 connected to RS-485 bus. */
#include
#include
#include
#include
#include
#include
#include PACe.h>
#include
#define F_CPU 6000000 /* 6MHz. */
#define MAX_RCV_LEN 128 /* Maximal receive message length. */
#define MAX_SND_LEN 128 /* Maximal send message length. */
#defineUART_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<
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 deaLEDover. */
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<
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();
}
}