?? m16-01.c
字號:
/*
www.avrdiy.com AVR單片機DIY網 潘小藝 CVAVR1.25.9
通訊規則:
01:時鐘7.3728 MHz/波特率9600/9個數據位/奇校驗/1個停止位/硬件多機通訊功能/
02:通訊連接采用硬件MAX485,雙向單工
03:MAX485的RE/DE并聯接到單片機的PD2腳(高電平發送/低電平接收)
04:所有MAX485的A腳并聯/B腳并聯/D腳接TXD/R腳接RXD
05:每個上行/下行的數據包的字節個數都是一樣的(通訊數據量)
06:數據包格式: 地址_數據1_數據2_數據3_數據n_CRC8校驗碼
07:主機使用查詢發送/接收中斷方式
08:從機使用發送中斷/接收中斷方式
09:總是由主機向從機下發一個數據包,從機收到數據包并校驗正確后向主機回復一個數據包
10:不管是主機還是從機,如果收到的數據包有任何錯誤,都將丟棄該數據包,等效于沒有接收
11:通訊采用主機輪詢方式,從機之間不能相互通訊,必須通過主機才能交換數據
12:無效地址是0,主機地址是1,從機地址是11.12.13...廣播地址是255
*/
#include <mega16.h>
#include <delay.h>
#include <usart.h>
#include <crc8.h>
#define address 1 //請在這里設定本機地址
#define amount 10 //設定通訊數據量
#define max485_out PORTD.2=1 //RS485輸出使能
#define max485_in PORTD.2=0 //RS485輸入使能
#define max485_RW_ok DDRD.2=1 //控制MAX485
#define data_bit8_1 UCSRB|=1 //數據的第8位
#define data_bit8_0 UCSRB&=254
#define data_in_error UCSRA&28 //檢測接收到的數據是否有錯誤
#define address_on UCSRA|=0x01 //打開地址篩選
#define address_off UCSRA&=254 //關閉地址篩選
#define address_bit8 UCSRB&2 //檢測數據的第8位
#define Txd_isr_off UCSRB&=191 //關閉發送結束中斷
unsigned char send[amount]; //發件箱
unsigned char inbox[amount]; //收件箱
unsigned char n=0; //記憶接收中斷的次數
unsigned char x=0;
//**************************************************************************************
void usart_out(unsigned char *datas,unsigned char n)
{
unsigned char i=0;
max485_out; //使MAX485處于發送狀態
while(i<n) //一共發送n個數據
{
if(i==0) data_bit8_1; else data_bit8_0;
UDR=*(datas+i); //裝載數據開始發送
while((UCSRA&64)==0); //等待發送結束
UCSRA|=64; //清除發送結束標志
i++; //發送次數統計
}
max485_in; //使MAX485處于接收狀態
}
//**************************************************************************************
interrupt[12] Rxd_isr(void) //接收中斷
{
if( data_in_error ){ n=UDR; n=0; address_on; } else //接收出錯就重新打開地址幀篩選功能
{
if( address_bit8 ) n=0; //檢測到地址信息時計數清零
inbox[n]=UDR; n++; //把接收到的數據保存到收件箱
if( inbox[0]==address ) address_off; else address_on; //地址篩選
}
}
//**************************************************************************************
void main(void)
{
usart_init();
Txd_isr_off; //主機沒必要使用發送結束中斷
max485_in;
max485_RW_ok;
DDRA=7; //通訊狀態指示
#asm("sei");
while(1)
{
x=~x; //測試用的變量
PORTA.0=~PORTA.0; //觀察單片機是否死機(供電一定要好)
//************************************與從機11對話****************************************
if(x) send[3]=0; else send[3]=25; //更新發件箱的數據(測試代碼)
send[0]=11; //指向從機地址
send[amount-1]=crc8(send,amount-1); //計算發件箱數據的crc8校驗碼
usart_out(send,amount); //將發件箱的數據send[]發送出去;
n=0; //計數復位,準備接收新數據
delay_ms(15); //等待從機回復數據,這個時間要計算好
if(n==amount && inbox[amount-1]==crc8(inbox,amount-1)) //接收正確處理與測試
{
PORTA.1=1; delay_ms(10); PORTA.1=0;
}
else //接收錯誤處理與測試
{
PORTA.2=1; delay_ms(10); PORTA.2=0;
}
//************************************與從機12對話****************************************
if(x) send[3]=10; else send[3]=15; //更新發件箱的數據(測試代碼)
send[0]=12; //指向從機地址
send[amount-1]=crc8(send,amount-1); //計算發件箱數據的crc8校驗碼
usart_out(send,amount); //將發件箱的數據send[]發送出去;
n=0; //計數復位,準備接收新數據
delay_ms(15); //等待從機回復數據,這個時間要計算好
if(n==amount && inbox[amount-1]==crc8(inbox,amount-1)) //接收正確處理與測試
{
PORTA.1=1; delay_ms(10); PORTA.1=0;
}
else //接收錯誤處理與測試
{
PORTA.2=1; delay_ms(10); PORTA.2=0;
}
}
} //end
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -