基于PIC的LIN總線設計
1.主節(jié)點
本文引用地址:http://m.butianyuan.cn/article/201611/315945.htm主節(jié)點資源:4個按鍵,采用9600波特率的UART,在發(fā)送同步間隔場時用4800!收發(fā)芯片:MCP201
2.從節(jié)點
從節(jié)點資源:UART,CCP捕捉 首先用接收引腳狀態(tài)判斷是否同步間隔場,用定時器1進行計時判斷同步間隔場是否合格,判斷合格后,用CCP模塊捕捉同步頭55H,同時計算波特率,之后打開UART進行數(shù)據(jù)接收!
程序如下:
1.MASTER
// LIN 總線設計
//---------------------------------------------
// 文件名: MASTER.c
// 版本: V1.0
// 日期: 25/12/06
// 功能: LIN總線主節(jié)點
// 編譯環(huán)境: HiTech PIC C compiler v.8.05
// 使用MCU: PIC16F877
// 通信速率: 9600
//---------------協(xié)議說明---------------------
//數(shù)據(jù)發(fā)送按照USART方式發(fā)送
//Lin協(xié)議說明:
//1.電平定義:
// 顯性電平:邏輯0
// 隱性電平:邏輯1
//2.數(shù)據(jù)組成
// 同步間隔場:至少13位的顯性電平,以及1個位的界定符(隱性電平)
// 同步場:0x55主機發(fā)送,從機通過定時器捕捉方式來計時計算波特率
// 數(shù)據(jù)場:
// a.標識符場:定義了報文的內容和長度,最高兩位是奇偶校驗位
// 位5和6是數(shù)據(jù)長度標識,低四位是地址標識符
// b.命令場:由2.4.8個數(shù)據(jù)字節(jié)組成,外加一個數(shù)據(jù)校驗場
// 保留標識符:(廣播標識符)
// "0x3c"主機請求,用于主機廣播命令,所有從機都接收
// "0x3d"從機響應,觸發(fā)所有從機節(jié)點順序向主機傳送數(shù)據(jù)
// 第一個數(shù)據(jù)場的00-7F保留,其余自由分配(程序里沒有遵循,實驗嘛呵呵)
//---------------------------------------------
#include
//---------------------------------------------
//--------------常量定義----------------------
#define Key1 RA0
#define Key2 RA1
#define Key3 RA2
#define Key4 RA3
#define CS RB1
#define STATUSIT(avr,s) ((unsigned)(&avr)*8+(s)) //絕對尋址定義
static bit C @ STATUSIT(STATUS,0); //對進位位進行定義
//----------------內存定義--------------------
unsigned char send[10]; //定義數(shù)據(jù)數(shù)組
unsigned char Counter; //發(fā)送個數(shù)計數(shù)
//--------------函數(shù)定義----------------------
void Picint(void); //初始化
void KeyScan(void); //鍵盤掃描
void Work1(void); //事件處理1
void Work2(void); //事件處理2
void Work3(void); //事件處理3
void Work4(void); //事件處理4
void interrupt SDI(void); //中斷函數(shù)
void Delay(unsigned int m); //延時函數(shù)
void Send(void); //數(shù)據(jù)發(fā)送
void SendSync(void); //同步間隔場和同步頭發(fā)送
void SendData(unsigned char asd); //發(fā)送數(shù)據(jù)場
unsigned char CheckSum(unsigned char as); //校驗和計算
void qushu();
//*********************************************
//主函數(shù)
//*********************************************
void main()
{
Picint();
while(1)
{
KeyScan(); //鍵盤掃描等待處理
}
}
//*********************************************
//初始化函數(shù)
//*********************************************
void Picint()
{
INTCON=0; //中斷定義
ADCON1=0x07; //定義A口為數(shù)字ioput模式
TRISA0=1; //鍵盤接口定義
TRISA1=1;
TRISA2=1;
TRISA3=1;
TRISB0=1; //中斷定義端口
TRISB1=0; //片選引腳
TXSTA=0x04; //USART模塊設置,使用高速波特率設置
RCSTA=0x80; //使能串口,并沒有開啟接收和發(fā)送
TRISC7=1; //數(shù)據(jù)輸入
TRISC6=0; //數(shù)據(jù)發(fā)送
CS=1; //片選
RC6=1;
}
//*********************************************
//數(shù)據(jù)發(fā)送 USART
//*********************************************
void Send()
{
//TXEN=1; //發(fā)送使能
SendSync(); //發(fā)送同步間隔場和同步頭
SendData(Counter); //發(fā)送的字節(jié)的數(shù)量
TXEN=0; //發(fā)送禁止
}
//*********************************************
//同步間隔場和同步頭發(fā)送
//*********************************************
void SendSync()
{
SPBRG=0x33; //同步間隔場按照4800發(fā)送
Delay(20);
TXEN=1;
Delay(20);
TXREG=0x80; //同步間隔場
while(1) //等待發(fā)送完畢
{
if(TXIF==1) break;
}
Delay(150);
SPBRG=0x19; //修改波特率為9600
Delay(50);
TXREG=0x55; //發(fā)送同步頭,用于從機進行波特率計算
while(1)
{
if(TXIF==1) break;
}
Delay(300); //延時準備發(fā)送數(shù)據(jù)
}
//*********************************************
//發(fā)送數(shù)據(jù)場
//*********************************************
void SendData(unsigned char asd)
{
unsigned char i;
TXREG=send[0]; //發(fā)送地址字節(jié)
while(1)
{
if(TXIF==1) break;
}
Delay(250); //延時,供從節(jié)點判斷是否是自己的地址
for(i=0;i {
TXREG=send[i+1]; //發(fā)送數(shù)據(jù)字節(jié),以及校驗字節(jié)
while(1)
{
if(TXIF==1) break;
}
Delay(100);
}
}
//*********************************************
//校驗和計算
//*********************************************
unsigned char CheckSum(unsigned char as)
{
//校驗和說明:
//是所有命令字節(jié)的和,但是如果相加的話產生進位位怎進位位加到和的最低位,最后結果取反
//從節(jié)點接收后同樣計算命令字節(jié)和,而后與校驗字節(jié)相加,其和必須等于0xFF;
unsigned char z,y;
y=0;
asm("bcf _STATUS,0"); //清進位位
for(z=0;z {
y=y+send[z+1];
if(C)
{
C=0; //清除進位位供下次使用
y=y+1; //如果進位位為1,則加到結果的最低位
}
}
y=~y; //按位取反
return y; //返回校驗和
}
//*********************************************
//鍵盤掃描函數(shù)
//*********************************************
void KeyScan()
{
if(Key1)
{
Delay(8000); //延時消抖
if(Key1) //確認鍵盤按下
{
while(Key1) //等待鍵盤釋放
{}
Work1(); //調用處理事件
}
}
//----------------------------------------------
if(Key2)
{
Delay(8000); //延時消抖
if(Key2) //確認鍵盤按下
{
while(Key2) //等待鍵盤釋放
{}
Work2(); //調用處理事件
}
}
//----------------------------------------------
if(Key3)
{
Delay(8000); //延時消抖
if(Key3) //確認鍵盤按下
{
while(Key3) //等待鍵盤釋放
{}
Work3(); //調用處理事件
}
}
//----------------------------------------------
if(Key4)
{
Delay(8000); //延時消抖
if(Key4) //確認鍵盤按下
{
while(Key4) //等待鍵盤釋放
{}
Work4(); //調用處理事件
}
}
}
//*********************************************
//事件處理
//*********************************************
void Work1()
{
send[0]=0xc1; //地址字節(jié)01,加上奇偶校驗為c1
send[1]=0x12; //命令字節(jié)1
send[2]=0x13; //命令字節(jié)2
Counter=3;
send[3]=CheckSum(Counter-1); //校驗和計算
Send();
}
//---------------------------------------------
void Work2()
{
send[0]=0xc1; //地址字節(jié)01,加上奇偶校驗為c1
send[1]=0x22; //命令字節(jié)1
send[2]=0x23;
Counter=3;
send[3]=CheckSum(Counter-1); //校驗和計算
Send();
}
//---------------------------------------------
void Work3()
{
send[0]=0xc1; //地址字節(jié)01,加上奇偶校驗為c1
send[1]=0x32; //命令字節(jié)1
send[2]=0x33;
Counter=3;
send[3]=CheckSum(Counter-1); //校驗和計算
Send();
}
//---------------------------------------------
void Work4()
{
send[0]=0xc1; //地址字節(jié)01,加上奇偶校驗為c1
send[1]=0x42; //命令字節(jié)1
send[2]=0x43;
Counter=3;
send[3]=CheckSum(Counter-1); //校驗和計算
Send();
}
//*********************************************
//延時函數(shù)
//*********************************************
void Delay( unsigned int m)
{
unsigned int i;
for(i=0;i<=m;i++)
{}
}
2.SLAVE
// Lin總線
//---------------------------------------------
// 文件名: slave(mew).c
// 版本: V1.0
// 日期: 13/12/06
// 功能: Lin 總線從節(jié)點
// 編譯環(huán)境: HiTech PIC C compiler v.8.05
// 使用MCU: PIC16F876(主頻4M)
// 接收說明:
// 首先判斷同步間隔場:符合要求進行下面操作,否則不予理睬并記錄錯誤
// 同步間隔采集合格:采集同步頭,主節(jié)點發(fā)送0x55,接收5個下降沿用于計算波特率
// 波特率計算成功:串口接收打開,進行ID接收,判斷是否自己ID不是放棄接收后面數(shù)據(jù)
// ID校驗成功:繼續(xù)接收后面數(shù)據(jù)場,并進行校驗,合格則進行相應操作,不合格記錄錯誤
// 初始化,進行下一個同步頭接收
//
//--------------------------------------------
#include
//--------------------------------------------
//---------------常量定義----------------------
#define TSync 1000 //同步間隔時間定義
#define FRest 0 //狀態(tài)復位0
#define FSync 1 //同步間隔場檢測
#define FSync1 2 //同步間隔場檢測狀態(tài)1
#define FTow 3 //同步頭接收
#define FId 4 //地址字節(jié)接收
#define FData 5 //數(shù)據(jù)接收
#define CS RC1 //片選引腳,高有效
#define RFIN RC2 //同步間隔場和同步場輸入端
#define Jiance RB7 //檢測引腳,測試時候用
//--------------數(shù)據(jù)定義-----------------------
unsigned char Data[9]; //數(shù)據(jù)接收數(shù)組
bank1 unsigned int TimeData[5]; //CCP1捕捉時間記錄函數(shù)
unsigned char RFdata; //狀態(tài)判斷
unsigned char FallCount; //同步頭的下降沿計數(shù)
unsigned int Sytime; //同步頭總時間保存
unsigned char RFstate; //接收狀態(tài)指示
unsigned char Towallow; //波特率計算允許標志
unsigned char DataCount; //接收數(shù)據(jù)字節(jié)個數(shù)寄存器
unsigned char y;
volatile bit IDcheck; //數(shù)據(jù)校驗合格標志
volatile bit Operate; //操作允許標志
volatile bit DatCheck; //數(shù)據(jù)和校驗成功標志
//bank1 unsigned char Stat @ 0x8f; //
unsigned char IDmoment ; //ID號暫時保存
//#define AVR(adr,biti) ((unsigned)(&adr)*8+(biti))
//#define ID0 AVR(Stat,0) //位定義
//#define ID1 AVR(Stat,1)
//#define ID2 AVR(Stat,2)
//#define ID3 AVR(Stat,3)
//#define ID4 AVR(Stat,4)
//#define ID5 AVR(Stat,5)
//#define ID6 AVR(Stat,6)
//#define ID7 AVR(Stat,7)
union
{
struct
{
unsigned b0:1; //0位,冒號后面的是占的位數(shù)
unsigned b1:1;
unsigned b2:1;
unsigned b3:1;
unsigned b4:1;
unsigned b5:1;
unsigned b6:1;
unsigned b7:1;
}onebit;
unsigned char allbit;
}all;
#define ID0 all.onebit.b0
#define ID1 all.onebit.b1
#define ID2 all.onebit.b2
#define ID3 all.onebit.b3
#define ID4 all.onebit.b4
#define ID5 all.onebit.b5
#define ID6 all.onebit.b6
#define ID7 all.onebit.b7
#define Stat all.allbit
/*
上面位定義也可以用絕對尋址位操作(但不建議)
或者結構和聯(lián)合體
應用方法:
all.onebit.b0=1; //給位0置1
all.allbit=0; //字節(jié)清0
*/
#define STATUSIT(avr,s) ((unsigned)(&avr)*8+(s)) //絕對尋址定義
static bit C @ STATUSIT(STATUS,0); //對進位位進行定義
union //16位時間計數(shù)器
{
unsigned int Counter;
unsigned char Time[2];
}ASD;
#define TimeL ASD.Time[0]
#define TimeH ASD.Time[1]
//--------------函數(shù)定義-----------------------
void Picint(void); //初始化
void Delay(void); //延時
void DataIn(void); //數(shù)據(jù)輸入判斷
void interrupt SDI(void); //中斷函數(shù)
void DataClear(void); //數(shù)組清0
void Dispose(void); //數(shù)據(jù)處理函數(shù)
void DataCdc(unsigned char asd); //數(shù)據(jù)校驗
//---------------------------------------------
//********************************************
//主函數(shù)
//********************************************
void main()
{
Picint();
while(1)
{
DataIn(); //數(shù)據(jù)查詢
if(Operate) //是否允許操作,進行相應操作
{
DataCdc(DataCount); //數(shù)據(jù)校驗是否合格
if(DatCheck)
{
Dispose();
}
}
}
}
//********************************************
//數(shù)據(jù)處理函數(shù)
//********************************************
void Dispose() //實驗,并沒具體做什么操作
{
if((Data[0]==0x12)&(Data[1]==0x13))
{
RB7=1;
}
if(Data[0]==0x22)
{
RB7=0;
}
}
//********************************************
//數(shù)據(jù)校驗
//********************************************
void DataCdc(unsigned char asd) //計算數(shù)據(jù)校驗和
{
unsigned char x,y;
DatCheck=0;
y=0;
asm("bcf _STATUS,0"); //清進位位
for(x=0;x<(asd-1);x++)
{
y=y+Data[x];
if(C)
{
C=0;
y=y+1;
}
}
y=y+Data[asd-1];
if(y==0xff) //校驗成功
{
DatCheck=1;
}
}
//********************************************
//中斷函數(shù)
//********************************************
void interrupt SDI() //用捕捉方式進行下降沿計數(shù),計算同步頭
{
if(CCP1IE&CCP1IF) //確認中斷
{
CCP1IF=0; //清中斷標志
TimeL=CCPR1L; //取數(shù)
TimeH=CCPR1H; //
TimeData[FallCount]=ASD.Counter; //寫入數(shù)組
FallCount++;
if(FallCount==5)
{
CCP1CON=0x00; //禁止CCP1捕捉
CCP1IE=0; //禁止CCP1中斷
CCP1IF=0; //清中斷標志
FallCount=0;
Towallow=1; //波特率計算允許
TMR1ON=0;
TMR1L=0;
TMR1H=0;
}
}
}
//********************************************
//數(shù)據(jù)輸入
//********************************************
void DataIn()
{
switch(RFstate)
{
case FSync: //同步間隔場檢測
RFdata=RFIN; //采樣值
if(RFdata==0) //下降沿檢測
{
TMR1L=0;
TMR1H=0;
TMR1ON=1; //開啟定時器1
RFstate=FSync1; //轉向狀態(tài)1
}
break;
case FSync1:
RFdata=RFIN;
if(RFdata==0)
{
if(TMR1IF) //在很長時間內如果主機的同步間隔場沒有完成產生錯誤
{
TMR1IF=0;
TMR1ON=0;
TMR1L=0;
TMR1H=0;
RFstate=FRest; //狀態(tài)機復位
}
}
else
{
TMR1ON=0; //關閉定時器
TimeL=TMR1L; //取出計數(shù)值
TimeH=TMR1H;
TMR1L=0; //計數(shù)器清0
TMR1H=0;
if(ASD.Counter>=TSync)
{
RFstate=FTow; //間隔場接收成功,下面接收同步頭
TMR1ON=1;
CCP1IE=1; //使能CCP1中斷
CCP1IF=0; //清中斷標志
CCP1CON=0x04; //配置捕捉方式,捕捉下降沿
}
else
{
RFstate=FRest; //否則指向復位
}
}
break;
case FTow: //同步頭接收
if(Towallow)
{
unsigned char i;
// SPBRG=0x19; //波特率設置
// RFstate=FId; //指向ID場接收
// CREN=1; //使能接收
Sytime=0;
for(i=0;i<4;i++) //循環(huán)計算總數(shù)據(jù)
{
Sytime=Sytime+(TimeData[i+1]-TimeData[i]);
}
Sytime=Sytime>>3; //除8計算
Sytime=(Sytime>>2)-1;
i=(unsigned char)Sytime;//強制轉換為字節(jié)型數(shù)據(jù),設定波特率
if((i<=30)&(i>=20)) //給定計算范圍
{
SPBRG=0x19; //波特率設置
RFstate=FId; //指向ID場接收
CREN=1; //使能接收
}
else
{
RFstate=FRest; //狀態(tài)復位
}
}
break;
case FId:
while(1) //等待數(shù)據(jù)接收
{
if(RCIF==1) break;
}
IDmoment=RCREG; //數(shù)據(jù)讀取,清中斷標
Stat=IDmoment;
if((Stat&0x0f)==0x01) //判斷是否是自己的ID地址,如果是自己的ID地址,校驗暫時沒加
{
Stat=IDmoment;
if((ID4==0)&(ID5==0))
{
DataCount=3; //兩個數(shù)據(jù)接收,同時還有1個校驗字節(jié)
}
if((ID4==1)&(ID5==0))
{
DataCount=3; //兩個數(shù)據(jù)接收,同時還有1個校驗字節(jié)
}
if((ID4==0)&(ID5==1))
{
DataCount=5; //四個數(shù)據(jù)接收,同時還有1個校驗字節(jié)
}
if((ID4==1)&(ID5==1))
{
DataCount=9; //八個數(shù)據(jù)接收,同時還有1個校驗字節(jié)
}
RFstate=FData; //指向數(shù)據(jù)接收
}
else
{
RFstate=FRest; //復位
}
break;
case FData: //數(shù)據(jù)接收
for(y=0;y
while(1)
{
if(RCIF==1) break;
}
Data[y]=RCREG; //讀取一個數(shù)據(jù)
}
RFstate=FRest; //復位,數(shù)據(jù)接收完畢
Operate=1; //允許操作
break;
default:
RFstate=FSync; //指向同步頭接收
Towallow=0; //波特率計算禁止
FallCount=0;
CCP1CON=0x00; //CCP禁止
TXEN=0; //禁止發(fā)送
CREN=0; //異步模式禁止接收
DataCount=0; //數(shù)據(jù)長度清0
Operate=0;
}
}
//********************************************
//初始化
//********************************************
void Picint()
{
INTCON=0; //清中斷源
GIE=1; //開總中斷
PEIE=1; //開外部中斷
RCIE=0; //禁止串口接收中斷
ADCON1=0x07; //定義A口為數(shù)字ioput模
//TRISA= 0xFF; //定義端口輸入輸出模式
TRISC1=0; //片選輸出端口
TRISC2=1; //捕捉模塊1輸入端
TRISB7=0; //測試使用的輸出引腳
RB7=0;
SPBRG=0x19; //定義波特率
TXSTA=0x04; //使能高速波特率,異步模式
RCSTA=0x80; //使能串口,禁止連續(xù)接收
TRISC6=1; //串口使能后這兩位必須設置為輸入高阻抗狀態(tài)
TRISC7=1;
T1CON=0x00; //定時器1初始化,用于捕捉功能
TMR1L=0x00;
TMR1H=0x00;
TMR1IE=0; //中斷標志以及中斷清除
TMR1IF=0;
CS=1; //片選置高
RFstate=FRest; //狀態(tài)機復位
Operate;
DataClear(); //數(shù)組清0
}
//********************************************
//數(shù)組清0 函數(shù)
//********************************************
void DataClear()
{
for(y=0;y<9;y++)
{
Data[y]=0;
}
}
評論