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