找回密码
 立即注册
查看: 33|回复: 0

49-LIN2总线主机收发测试,STC32G144K246实验箱演示程序

[复制链接]
  • 打卡等级:常住居民I
  • 打卡总天数:78
  • 最近打卡:2026-07-21 13:27:09
已绑定手机

231

主题

168

回帖

1069

积分

版主

积分
1069
发表于 2026-7-3 14:13:09 | 显示全部楼层 |阅读模式
49-LIN2总线主机收发测试,STC32G144K246实验箱演示程序
主程序main.C代码如下(汇编版本在附件中):


/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com  -----------------------------------------*/
/*---------------------------------------------------------------------*/

/*************  功能说明    **************

本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

Lin主机总线收发测试用例,默认LIN脚位选择,P8.4,P8.5.

按一下P32口按键, 主机发送完整一帧数据.
按一下P33口按键, 主机发送帧头并获取从机应答数据(合并成一串完整的帧).

默认传输速率:9600波特率, 用户可自行修改.

下载时, 默认时钟 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 TX_BUF[8];
u8 RX_BUF[8];

u8 Key1_cnt;
u8 Key2_cnt;
bit Key1_Flag;
bit Key2_Flag;

/****************  本地函数声明  **************/

void LinInit();
void LinSendMsg(u8 lid, u8 *pdat);
void LinSendHeader(u8 lid);
void LinReadMsg(u8 *pdat);
void delay_ms(u16 ms);
void UartInit(void);

/********************* 主函数 *************************/
void main(void)
{
    u8 i;

    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P3M1 = 0x00;   P3M0 = 0x02;   //设置为准双向口,P3.1推挽输出
    P4M1 = 0x00;   P4M0 = 0xc0;   //设置为准双向口,P4.6,P4.7推挽输出
    P8M1 = 0x00;   P8M0 = 0x20;   //设置为准双向口,P8.5推挽输出
    P9M1 = 0x00;   P9M0 = 0x02;   //设置为准双向口,P9.1推挽输出

    P3PU = 0x0c;          //P3.2,P3.3 按键脚开启内部上拉
    P8PU = 0x30;          //LIN_TX, LIN_RX 脚开启内部上拉

    Lin_ID = 0x32;
    LinInit();
    UartInit();
    EA = 1;               //打开总中断

    NORMAL_MODE();
    TX_BUF[0] = 0x81;
    TX_BUF[1] = 0x22;
    TX_BUF[2] = 0x33;
    TX_BUF[3] = 0x44;
    TX_BUF[4] = 0x55;
    TX_BUF[5] = 0x66;
    TX_BUF[6] = 0x77;
    TX_BUF[7] = 0x88;

    while(1)
    {
        delay_ms(1);
        if(!P32)
        {
            if(!Key1_Flag)
            {
                Key1_cnt++;
                if(Key1_cnt > 50)
                {
                    P46 = ~P46;
                    Key1_Flag = 1;
                    LinSendMsg(Lin_ID, TX_BUF); //发送一串完整数据
                }
            }
        }
        else
        {
            Key1_cnt = 0;
            Key1_Flag = 0;
        }

        if(!P33)
        {
            if(!Key2_Flag)
            {
                Key2_cnt++;
                if(Key2_cnt > 50)
                {
                    P47 = ~P47;
                    Key2_Flag = 1;
                    LinSendHeader(0x15);        //发送帧头,获取数据帧,组成一个完整的帧
                    LinReadMsg(RX_BUF);         //接收Lin总线从机发送的应答数据
                    printf("LIN2 Read: ");
                    for(i=0; i<FRAME_LEN; i++)  printf("0x%02x ",RX_BUF);    //从串口输出收到的数据
printf("\r\n");
                }
            }
        }
        else
        {
            Key2_cnt = 0;
            Key2_Flag = 0;
        }
    }
}

//========================================================================
// 函数: 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
// 日期: 2021-01-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
// 日期: 2021-01-05
// 备注:
//========================================================================
void LinWriteReg(u8 addr, u8 dat)
{
    LINAR = addr;
    LINDR = dat;
}

//========================================================================
// 函数: void LinReadMsg(u8 *pdat)
// 描述: Lin读取数据函数。
// 参数: *pdat: 接收数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-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
// 日期: 2021-01-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
// 日期: 2021-01-05
// 备注:
//========================================================================
void LinSetID(u8 lid)
{
    LinWriteReg(LID,lid);       //设置总线ID
}

//========================================================================
// 函数: u8 GetLinError(void)
// 描述: 获取LIN总线错误寄存器状态。
// 参数: none.
// 返回: 错误寄存器状态.
// 版本: VER1.0
// 日期: 2021-01-05
// 备注:
//========================================================================
u8 GetLinError(void)
{
    u8 sta;
    sta = LinReadReg(LER);      //读取清除错误寄存器
    return sta;
}

//========================================================================
// 函数: u8 WaitLinReady(void)
// 描述: 等待LIN总线就绪。
// 参数: none.
// 返回: LIN总线状态.
// 版本: VER1.0
// 日期: 2021-01-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
// 日期: 2021-01-05
// 备注:
//========================================================================
void SendAbortCmd(void)
{
    LinWriteReg(LCR,0x80);      //主模式 Send Abort
}

//========================================================================
// 函数: void SendHeadCmd(void)
// 描述: 主模式发送Lin总线Header函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-05
// 备注:
//========================================================================
void SendHeadCmd(void)
{
    LinWriteReg(LCR,0x81);      //主模式 Send Header
}

//========================================================================
// 函数: void SendDatCmd(void)
// 描述: 主模式发送Lin总线数据函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-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
// 日期: 2021-01-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
// 日期: 2021-01-05
// 备注:
//========================================================================
void ResponseRxCmd(void)
{
    u8 lcr_val;
    lcr_val = 0x03+(LIN_MODE<<6)+(FRAME_LEN<<2);
    LinWriteReg(LCR,lcr_val);
}

//========================================================================
// 函数: void LinSendMsg(u8 lid, u8 *pdat)
// 描述: Lin主机发送完整帧函数。
// 参数: lid: Lin ID; *pdat: 发送数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-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
// 日期: 2021-01-05
// 备注:
//========================================================================
void LinSendHeader(u8 lid)
{
    LinSetID(lid);              //设置发送Response从机总线ID

    SendHeadCmd();              //主模式 send header
    WaitLinReady();             //等待ready状态
    GetLinError();              //读取清除错误寄存器

    ResponseRxCmd();            //RX response
    WaitLinReady();             //等待ready状态
    GetLinError();              //读取清除错误寄存器
}

//========================================================================
// 函数: void LinSetBaudrate(u16 brt)
// 描述: Lin总线波特率设置函数。
// 参数: brt: 波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-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
// 日期: 2021-01-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()
// 描述: Lin初始化函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-05
// 备注:
//========================================================================
void LinInit()
{
    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,0x00);          //LIE中断使能寄存器
    LinSetBaudrate(9600);           //设置波特率
    LinSetHeadDelay(0x01,0x01);     //设置帧头延时
}

//========================================================================
// 函数: void LinBUS_Interrupt(void) interrupt LIN2_VECTOR
// 描述: Lin总线中断函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-01-05
// 备注:
//========================================================================
void LinBUS_Interrupt(void) interrupt LIN2_VECTOR
{
    u8 isr;
    u8 arTemp;
    arTemp = LINAR;     //LINAR 现场保存,避免主循环里写完 LINAR 后产生中断,在中断里修改了 LINAR 内容

    isr = LinReadReg(LSR);      //读取寄存器清除状态标志位
//    if((isr & 0x03) == 0x03)
//    {
//        isr = LinReadReg(LER);
//        if(isr == 0x00)        //No Error
//        {
//            P46 = ~P46;
//        }
//    }

    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;
}

49-LIN2总线主机收发测试.zip (12 KB, 下载次数: 0)

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-7-22 10:20 , Processed in 0.066070 second(s), 42 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表