- 打卡等级:常住居民I
- 打卡总天数:78
- 最近打卡:2026-07-21 13:27:09
已绑定手机
版主
- 积分
- 1069
|
45.1-LIN1-LIN2主从收发测试,STC32G144K246实验箱演示程序
主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com -----------------------------------------*/
/*---------------------------------------------------------------------*/
/************* 功能说明 **************
本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
Lin主机总线收发测试用例,LIN1脚位选择,P5.2,P5.3;LIN2脚位选择,P8.4,P8.5
按一下P32口按键, 主机发送完整一帧数据.
按一下P33口按键, 主机发送帧头并获取从机应答数据(合并成一串完整的帧).
默认传输速率:9600波特率, 用户可自行修改.
注意:LIN收到帧头后需要进行"RX response"后才能收到数据,所以两个LIN同时使用时需要通过中断发送"RX response"命令才能及时收到数据。
下载时, 默认时钟 48MHz (用户可自行修改频率).
******************************************/
#include "..\comm\STC32G144K246.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**************** 用户定义宏 ****************/
#define MAIN_Fosc 48000000UL
#define Baudrate 115200L //设置串口波特率
#define TM (65536 -(MAIN_Fosc/Baudrate/4))
#define PrintUart 1 //1:printf 使用 UART1; 2:printf 使用 UART2
#define LIN_MODE 1 //0: LIN2.1; 1: LIN1.3
#define FRAME_LEN 8 //数据长度: 8 字节
/**************** 本地引脚定义 **************/
#define NORMAL_MODE() P9SETB = 0x02 //P91 = 1
#define SLEEP_MODE() P9CLRB = 0x02 //P91 = 0
/**************** 本地常量声明 **************/
/**************** 本地变量声明 **************/
u8 Lin_ID;
u8 TX1_BUF[8];
u8 RX1_BUF[8];
u8 TX2_BUF[8];
u8 RX2_BUF[8];
u8 Read_ID1;
u8 Read_ID2;
u8 Lin1ReadMsg;
bit LinRx1Flag;
bit Lin1SendMsg;
bit LinTx2Flag;
bit LinRx2Flag;
u8 Key1_cnt;
u8 Key2_cnt;
bit Key1_Flag;
bit Key2_Flag;
/**************** 本地函数声明 **************/
void Lin1Init(void);
void Lin2Init(void);
void LinSendMsg(u8 lid, u8 *pdat);
void LinSendHeader(u8 lid);
void LinReadMsg(u8 *pdat);
void LinTxResponse(u8 *pdat);
void delay_ms(u16 ms);
void UartInit(void);
/********************* 主函数 *************************/
void main(void)
{
u8 i,isr;
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P1M1 = 0x00; P1M0 = 0x02; //设置为准双向口,P1.1推挽输出
P3M1 = 0x00; P3M0 = 0x02; //设置为准双向口,P3.1推挽输出
P4M1 = 0x00; P4M0 = 0xc0; //设置为准双向口,P4.6,P4.7推挽输出
P5M1 = 0x00; P5M0 = 0x08; //设置为准双向口,P5.3推挽输出
P8M1 = 0x00; P8M0 = 0x20; //设置为准双向口,P8.5推挽输出
P9M1 = 0x00; P9M0 = 0x02; //设置为准双向口,P9.1推挽输出
P3PU = 0x0c; //P3.2,P3.3 按键脚开启内部上拉
P5PU = 0x0c; //LIN1_TX, LIN1_RX 脚开启内部上拉
P8PU = 0x30; //LIN2_TX, LIN2_RX 脚开启内部上拉
Lin_ID = 0x32;
Lin1Init();
Lin2Init();
UartInit();
EA = 1; //打开总中断
NORMAL_MODE();
TX1_BUF[0] = 0x11;
TX1_BUF[1] = 0x12;
TX1_BUF[2] = 0x13;
TX1_BUF[3] = 0x14;
TX1_BUF[4] = 0x15;
TX1_BUF[5] = 0x16;
TX1_BUF[6] = 0x17;
TX1_BUF[7] = 0x18;
TX2_BUF[0] = 0x21;
TX2_BUF[1] = 0x22;
TX2_BUF[2] = 0x23;
TX2_BUF[3] = 0x24;
TX2_BUF[4] = 0x25;
TX2_BUF[5] = 0x26;
TX2_BUF[6] = 0x27;
TX2_BUF[7] = 0x28;
while(1)
{
delay_ms(1);
if(!P32)
{
if(!Key1_Flag)
{
Key1_cnt++;
if(Key1_cnt > 50)
{
P46 = ~P46;
Key1_Flag = 1;
LINSEL = 0; //选择LIN1
Lin1SendMsg = 1; //通过中断判断ready状态,减少等待时间
LinSendMsg(Lin_ID, TX1_BUF); //发送一串完整数据
Lin_ID++;
TX1_BUF[0]++;
}
}
}
else
{
Key1_cnt = 0;
Key1_Flag = 0;
}
if(!P33)
{
if(!Key2_Flag)
{
Key2_cnt++;
if(Key2_cnt > 50)
{
P47 = ~P47;
Key2_Flag = 1;
LINSEL = 0; //选择LIN1
Lin1ReadMsg = 1;
LinSendHeader(0x13); //发送帧头,获取数据帧,组成一个完整的帧
}
}
}
else
{
Key2_cnt = 0;
Key2_Flag = 0;
}
if(LinRx1Flag)
{
LinRx1Flag = 0;
Lin1ReadMsg = 0;
LINSEL = 0; //选择LIN1
LinReadMsg(RX1_BUF); //接收Lin总线数据
printf("LIN1 Read ID=0x%02x: ",Read_ID1);
for(i=0; i<FRAME_LEN; i++) printf("0x%02x ",RX1_BUF); //从串口输出收到的数据
printf("\r\n");
}
if(LinTx2Flag) //判断是否从机响应ID
{
LinTx2Flag = 0;
LINSEL = 1; //选择LIN2
LinTxResponse(TX2_BUF); //返回响应数据
printf("LIN2 Send response.\r\n",isr);
TX2_BUF[0]++;
}
if(LinRx2Flag)
{
LinRx2Flag = 0;
LINSEL = 1; //选择LIN2
LinReadMsg(RX2_BUF); //接收Lin总线数据
printf("LIN2 Read ID=0x%02x: ",Read_ID2);
for(i=0; i<FRAME_LEN; i++) printf("0x%02x ",RX2_BUF); //从串口输出收到的数据
printf("\r\n");
}
}
}
//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注: 由于芯片使能了Cache功能,软件延时时间可能不太准确
//========================================================================
void delay_ms(u16 ms)
{
u16 i;
do{
i = MAIN_Fosc / 6000;
while(--i);
}while(--ms);
}
//========================================================================
// 函数: u8 ReadReg(u8 addr)
// 描述: Lin功能寄存器读取函数。
// 参数: Lin功能寄存器地址.
// 返回: Lin功能寄存器数据.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
u8 LinReadReg(u8 addr)
{
u8 dat;
LINAR = addr;
dat = LINDR;
return dat;
}
//========================================================================
// 函数: void WriteReg(u8 addr, u8 dat)
// 描述: Lin功能寄存器配置函数。
// 参数: Lin功能寄存器地址, Lin功能寄存器数据.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinWriteReg(u8 addr, u8 dat)
{
LINAR = addr;
LINDR = dat;
}
//========================================================================
// 函数: void LinReadMsg(u8 *pdat)
// 描述: Lin读取数据函数。
// 参数: *pdat: 接收数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinReadMsg(u8 *pdat)
{
u8 i;
LinWriteReg(LSEL,0x80); //地址自增,从0开始
for(i=0;i<FRAME_LEN;i++)
{
pdat = LinReadReg(LBUF);
}
}
//========================================================================
// 函数: u16 LinSetMsg(u8 *pdat)
// 描述: Lin设置数据函数。
// 参数: *pdat: 设置数据缓冲区.
// 返回: Lin ID.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSetMsg(u8 *pdat)
{
u8 i;
LinWriteReg(LSEL,0x80); //地址自增,从0开始
for(i=0;i<FRAME_LEN;i++)
{
LinWriteReg(LBUF,pdat);
}
}
//========================================================================
// 函数: void LinSetID(u8 lid)
// 描述: 设置LIN ID函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSetID(u8 lid)
{
LinWriteReg(LID,lid); //设置总线ID
}
//========================================================================
// 函数: u8 GetLinError(void)
// 描述: 获取LIN总线错误寄存器状态。
// 参数: none.
// 返回: 错误寄存器状态.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
u8 GetLinError(void)
{
u8 sta;
sta = LinReadReg(LER); //读取清除错误寄存器
return sta;
}
//========================================================================
// 函数: u8 WaitLinReady(void)
// 描述: 等待LIN总线就绪。
// 参数: none.
// 返回: LIN总线状态.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
//u8 WaitLinReady(void)
//{
// u8 lsr;
// do{
// lsr = LinReadReg(LSR);
// }while(!(lsr & 0x02)); //判断ready状态
// return lsr;
//}
//========================================================================
// 函数: void SendAbortCmd(void)
// 描述: 主模式发送Lin总线Abort函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void SendAbortCmd(void)
{
LinWriteReg(LCR,0x80); //主模式 Send Abort
}
//========================================================================
// 函数: void SendHeadCmd(void)
// 描述: 主模式发送Lin总线Header函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void SendHeadCmd(void)
{
LinWriteReg(LCR,0x81); //主模式 Send Header
}
//========================================================================
// 函数: void SendDatCmd(void)
// 描述: 主模式发送Lin总线数据函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void SendDatCmd(void)
{
u8 lcr_val;
lcr_val = 0x82+(LIN_MODE<<6)+(FRAME_LEN<<2);
LinWriteReg(LCR,lcr_val);
}
//========================================================================
// 函数: void ResponseTxCmd(void)
// 描述: 从模式发送Lin总线Tx Response函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void ResponseTxCmd(void)
{
u8 lcr_val;
lcr_val = 0x02+(LIN_MODE<<6)+(FRAME_LEN<<2);
LinWriteReg(LCR,lcr_val);
}
//========================================================================
// 函数: void ResponseRxCmd(void)
// 描述: 从模式发送Lin总线Rx Response函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void ResponseRxCmd(void)
{
u8 lcr_val;
lcr_val = 0x03+(LIN_MODE<<6)+(FRAME_LEN<<2);
LinWriteReg(LCR,lcr_val);
}
//========================================================================
// 函数: void LinTxResponse(u8 *pdat)
// 描述: Lin从机发送应答数据,跟主机发送的Header拼成一个完整的帧。
// 参数: *pdat: 发送数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinTxResponse(u8 *pdat)
{
LinSetMsg(pdat);
ResponseTxCmd(); //TX response
// WaitLinReady(); //等待ready状态
// GetLinError(); //读取清除错误寄存器
}
//========================================================================
// 函数: void LinSendMsg(u8 lid, u8 *pdat)
// 描述: Lin主机发送完整帧函数。
// 参数: lid: Lin ID; *pdat: 发送数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSendMsg(u8 lid, u8 *pdat)
{
LinSetID(lid); //设置总线ID
LinSetMsg(pdat);
SendHeadCmd(); //主模式 Send Seader
// WaitLinReady(); //等待ready状态
// GetLinError(); //读取清除错误寄存器
// SendDatCmd(); //Send Data
// WaitLinReady(); //等待ready状态
// GetLinError(); //读取清除错误寄存器
}
//========================================================================
// 函数: void LinSendHeader(u8 lid)
// 描述: Lin主机发送Header,由从机发送应答数据,拼成一个完整的帧。
// 参数: lid: 发送应答从机的总线ID.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSendHeader(u8 lid)
{
LinSetID(lid); //设置发送Response从机总线ID
SendHeadCmd(); //主模式 send header
}
//========================================================================
// 函数: void LinSetBaudrate(u16 brt)
// 描述: Lin总线波特率设置函数。
// 参数: brt: 波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSetBaudrate(u16 brt)
{
u16 tmp;
tmp = (MAIN_Fosc >> 4) / brt;
LinWriteReg(DLH,(u8)(tmp>>8));
LinWriteReg(DLL,(u8)tmp);
}
//========================================================================
// 函数: void LinSetHeadDelay(u8 base_ms, u8 prescaler)
// 描述: Lin总线设置帧头延时函数。
// 参数: base_ms:延时计数, prescaler:延时分频.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void LinSetHeadDelay(u8 base_ms, u8 prescaler)
{
u16 tmp;
tmp = (MAIN_Fosc * base_ms) / 1000;
LinWriteReg(HDRH,(u8)(tmp>>8));
LinWriteReg(HDRL,(u8)tmp); //设置帧头延时计数
LinWriteReg(HDP,prescaler); //设置帧头延时分频
}
//========================================================================
// 函数: void LinInit(void)
// 描述: Lin初始化函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void Lin1Init(void)
{
P_SW1 = (P_SW1 & 0xfc) | 0x01; //LIN脚位选择,0x00: P0.2,P0.3, 0x01: P5.2,P5.3, 0x02: P4.6,P4.7, 0x03: P7.2,P7.3
LINSEL = 0; //选择LIN1
LINICR |= 0x02; //LIN1模块中断使能
LINEN = 1; //LIN1模块被使能
GetLinError(); //读取清除错误寄存器
LinWriteReg(LIE,0x0F); //LIE中断使能寄存器
LinSetBaudrate(9600); //设置波特率
LinSetHeadDelay(0x01,0x01); //设置帧头延时
}
void Lin2Init(void)
{
P_SWX2 = (P_SWX2 & 0xcf) | 0x30;//LIN脚位选择,0x00: P0.6,P0.7, 0x10: P2.6,P2.7, 0x20: P6.2,P6.3, 0x30: P8.4,P8.5
LINSEL = 1; //选择LIN2
LINICR |= 0x20; //LIN2模块中断使能
LIN2EN = 1; //LIN2模块被使能
GetLinError(); //读取清除错误寄存器
LinWriteReg(LIE,0x0F); //LIR中断使能寄存器
LinSetBaudrate(9600); //设置波特率
LinSetHeadDelay(0x02,0x03); //设置帧头延时
}
//========================================================================
// 函数: void Lin1BUS_Interrupt(void) interrupt LIN1_VECTOR
// 描述: Lin总线中断函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void Lin1BUS_Interrupt(void) interrupt LIN1_VECTOR
{
u8 isr;
u8 arTemp;
bit linSel;
arTemp = LINAR; //LINAR 现场保存,避免主循环里写完 LINAR 后产生中断,在中断里修改了 LINAR 内容
linSel = LINSEL;
LINSEL = 0; //选择LIN1
isr = LinReadReg(LSR); //读取寄存器清除状态标志位
if((isr & 0x07) == 0x02)
{
Read_ID1 = LinReadReg(LID);
if(Lin1ReadMsg == 1)
{
ResponseRxCmd(); //RX response
Lin1ReadMsg = 2;
}
else if(Lin1ReadMsg == 2)
{
LinRx1Flag = 1; //开始接收数据
}
if(Lin1SendMsg == 1)
{
SendDatCmd(); //Send Data
Lin1SendMsg = 0;
}
}
isr = LinReadReg(LER); //读取清除错误寄存器
LINSEL = linSel; //LINSEL现场恢复
LINAR = arTemp; //LINAR 现场恢复
}
//========================================================================
// 函数: void Lin2BUS_Interrupt(void) interrupt LIN2_VECTOR
// 描述: Lin总线中断函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-10-05
// 备注:
//========================================================================
void Lin2BUS_Interrupt(void) interrupt LIN2_VECTOR
{
u8 isr;
u8 arTemp;
u8 linSel;
static bit Lin2SendMsg=0;
arTemp = LINAR; //LINAR 现场保存,避免主循环里写完 LINAR 后产生中断,在中断里修改了 LINAR 内容
linSel = AUXR2;
LINSEL = 1; //选择LIN2
isr = LinReadReg(LSR);
if((isr & 0x07) == 0x03)
{
Read_ID2 = LinReadReg(LID);
if(Read_ID2 == 0x13) //判断是否从机响应ID
{
LinTx2Flag = 1;
}
else
{
ResponseRxCmd(); //RX response
Lin2SendMsg = 1;
}
}
else if(((isr & 0x07) == 0x02) && Lin2SendMsg)
{
Lin2SendMsg = 0;
LinRx2Flag = 1;
}
isr = LinReadReg(LER); //读取清除错误寄存器
AUXR2 = linSel; //LINSEL现场恢复
LINAR = arTemp; //LINAR 现场恢复
}
/******************** 串口打印函数 ********************/
void UartInit(void)
{
#if(PrintUart == 1)
SCON = (SCON & 0x3f) | 0x40;
T1x12 = 1; //定时器时钟1T模式
S1BRT = 0; //串口1选择定时器1为波特率发生器
TL1 = TM;
TH1 = TM>>8;
TR1 = 1; //定时器1开始计时
// SCON = (SCON & 0x3f) | 0x40;
// T2L = TM;
// T2H = TM>>8;
// AUXR |= 0x15; //串口1选择定时器2为波特率发生器
#else
S2_S = 0; //UART2 switch to: 0: P1.0 P1.1, 1: P4.6 P4.7
S2CFG |= 0x01; //使用串口2时,W1位必需设置为1,否则可能会产生不可预期的错误
S2CON = (S2CON & 0x3f) | 0x40;
T2L = TM;
T2H = TM>>8;
AUXR |= 0x14; //定时器2时钟1T模式,开始计时
#endif
}
void UartPutc(unsigned char dat)
{
#if(PrintUart == 1)
SBUF = dat;
while(TI == 0);
TI = 0;
#else
S2BUF = dat;
while(S2TI == 0);
S2TI = 0; //Clear Tx flag
#endif
}
char putchar(char c)
{
UartPutc(c);
return c;
}
45.1-LIN1-LIN2主从收发测试.zip
(13.38 KB, 下载次数: 0)
|
|