芯启元 发表于 2026-7-3 13:42:54

45.2-LIN1-LIN2主从收发测试-软件实现自动波特率,STC32G144K246实验箱演示程序

45.2-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

在LIN总线空闲时触发波特率采样,收到LIN总线信号时,开始采集同步场信号宽度,根据采样结果调整LIN2(从机)波特率。

按一下P32口按键, 主机发送完整一帧数据, 并触发启动波特率采样.
按一下P33口按键, 主机发送帧头并获取从机应答数据(合并成一串完整的帧).

默认传输速率:LIN1:19200波特率, LIN2:9600波特率, 自动调整波特率后就能正常通信.

注意:LIN收到帧头后需要进行"RX response"后才能收到数据,所以两个LIN同时使用时需要通过中断发送"RX response"命令才能及时收到数据。

下载时, 选择IRC频率 48MHz,主时钟使用 PLL 90MHz 时钟频率.

******************************************/

#include "..\comm\STC32G144K246.h"

typedef   unsigned char    u8;
typedef   unsigned int    u16;
typedef   unsigned long   u32;

/****************用户定义宏****************/

#define SEL_HPLL1       1
#define SEL_HPLL2       2
#define HPLL_SEL      SEL_HPLL2

#if(HPLL_SEL==SEL_HPLL1)
    #define MAIN_Fosc   120000000L //定义主时钟(超频)
#else
    #define MAIN_Fosc   90000000L//定义主时钟
#endif

#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;
u8 RX1_BUF;
u8 TX2_BUF;
u8 RX2_BUF;

u8 Read_ID1;
u8 Read_ID2;

u8Lin1ReadMsg;
bit LinRx1Flag;

bit LinTx2Flag;
bit LinRx2Flag;

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

u16 T0Cnt;
u8 FallingCnt;
bit bDetFlag;

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

void HPLL_config(void);
void Lin1Init(void);
void Lin2Init(void);
void LinWriteReg(u8 addr, u8 dat);
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 IOINT_Config(void);
void Timer0_Init(void);
void DetStart(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 脚开启内部上拉

    HPLL_config();

    Lin_ID = 0x32;
    Lin1Init();
    Lin2Init();
    UartInit();
    IOINT_Config();
    Timer0_Init();
    EA = 1;               //打开总中断

    NORMAL_MODE();
    TX1_BUF = 0x11;
    TX1_BUF = 0x12;
    TX1_BUF = 0x13;
    TX1_BUF = 0x14;
    TX1_BUF = 0x15;
    TX1_BUF = 0x16;
    TX1_BUF = 0x17;
    TX1_BUF = 0x18;

    TX2_BUF = 0x21;
    TX2_BUF = 0x22;
    TX2_BUF = 0x23;
    TX2_BUF = 0x24;
    TX2_BUF = 0x25;
    TX2_BUF = 0x26;
    TX2_BUF = 0x27;
    TX2_BUF = 0x28;

    while(1)
    {
      delay_ms(1);
      if(!P32)
      {
            if(!Key1_Flag)
            {
                Key1_cnt++;
                if(Key1_cnt > 50)
                {
                  DetStart();   //在总线空闲时,触发启动波特率采样

                  P46 = ~P46;
                  Key1_Flag = 1;
                  LINSEL = 0;                     //选择LIN1
                  LinSendMsg(Lin_ID, TX1_BUF);    //发送一串完整数据
                  Lin_ID++;
                  TX1_BUF++;
                }
            }
      }
      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++;
      }
      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");
      }

      if(bDetFlag)
      {
            bDetFlag = 0;
            LINSEL = 1;               //选择LIN2
            LinWriteReg(DLH,(u8)(T0Cnt>>8));
            LinWriteReg(DLL,(u8)T0Cnt); //重新设置波特率
            printf("T0Cnt=%u\r\n",T0Cnt);
      }
    }
}

//========================================================================
// 函数: void HPLL_config(void)
// 描述: PLL时钟配置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注:
//========================================================================
void HPLL_config(void)
{
#if(HPLL_SEL==SEL_HPLL2)
    WTST = 2;         //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:360MHz/2/2=90MHz, 读Flash速度:90MHz/(1+2)=30MHz

    HPLLCR |= 0x80;   //使能HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)

                        //首先需要将HIRC主频调节到48MHz
    HPLL2CR &= ~0x10;   //选择HPLL2输入时钟源为HIRC
//    HPLL2CR |= 0x10;    //选择HPLL2输入时钟源为IRCM
    HPLL2PDIV = 8;      //设置HPLL2输入时钟预分频为8(HPLL输入频率必须为6MHz)
//    HPLL2CR |= 0x00;    //HPLL2=6MHz*52=312MHz
//    HPLL2CR |= 0x01;    //HPLL2=6MHz*54=324MHz
//    HPLL2CR |= 0x02;    //HPLL2=6MHz*56=336MHz
//    HPLL2CR |= 0x03;    //HPLL2=6MHz*58=348MHz
    HPLL2CR |= 0x04;    //HPLL2=6MHz*60=360MHz
//    HPLL2CR |= 0x05;    //HPLL2=6MHz*62=372MHz
//    HPLL2CR |= 0x06;    //HPLL2=6MHz*64=384MHz
//    HPLL2CR |= 0x07;    //HPLL2=6MHz*66=396MHz
//    HPLL2CR |= 0x08;    //HPLL2=6MHz*68=408MHz
//    HPLL2CR |= 0x09;    //HPLL2=6MHz*70=420MHz
//    HPLL2CR |= 0x0a;    //HPLL2=6MHz*72=432MHz
//    HPLL2CR |= 0x0b;    //HPLL2=6MHz*74=444MHz
//    HPLL2CR |= 0x0c;    //HPLL2=6MHz*76=456MHz
//    HPLL2CR |= 0x0d;    //HPLL2=6MHz*78=468MHz
//    HPLL2CR |= 0x0e;    //HPLL2=6MHz*80=480MHz
//    HPLL2CR |= 0x0f;    //HPLL2=6MHz*82=492MHz
    HPLL2CR |= 0x20;    //高速外设时钟选择 HPLL2/2
    HPLL2CR |= 0x80;    //使能HPLL2

    HPLLCR &= ~0x80;    //关闭HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)

    CLKDIV = 2;         //系统时钟 = 主时钟源/2 = HPLL2/2/2 = 90MHz
    CLKSEL = 0x08;      //选择HPLL2/2作为主时钟源

#else
    WTST = 3;         //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:480MHz/2/2=120MHz, 读Flash速度:120MHz/(1+3)=30MHz
                        //首先需要将HIRC主频调节到48MHz
    HPLLCR &= ~0x10;    //选择HPLL输入时钟源为HIRC
//    HPLLCR |= 0x10;   //选择HPLL输入时钟源为IRCM
    HPLLPDIV = 8;       //设置HPLL输入时钟预分频为8(HPLL输入频率必须为6MHz)
//    HPLLCR |= 0x00;   //HPLL=6MHz*52=312MHz
//    HPLLCR |= 0x01;   //HPLL=6MHz*54=324MHz
//    HPLLCR |= 0x02;   //HPLL=6MHz*56=336MHz
//    HPLLCR |= 0x03;   //HPLL=6MHz*58=348MHz
//    HPLLCR |= 0x04;   //HPLL=6MHz*60=360MHz
//    HPLLCR |= 0x05;   //HPLL=6MHz*62=372MHz
//    HPLLCR |= 0x06;   //HPLL=6MHz*64=384MHz
//    HPLLCR |= 0x07;   //HPLL=6MHz*66=396MHz
//    HPLLCR |= 0x08;   //HPLL=6MHz*68=408MHz
//    HPLLCR |= 0x09;   //HPLL=6MHz*70=420MHz
//    HPLLCR |= 0x0a;   //HPLL=6MHz*72=432MHz
//    HPLLCR |= 0x0b;   //HPLL=6MHz*74=444MHz
//    HPLLCR |= 0x0c;   //HPLL=6MHz*76=456MHz
//    HPLLCR |= 0x0d;   //HPLL=6MHz*78=468MHz
    HPLLCR |= 0x0e;   //HPLL=6MHz*80=480MHz
//    HPLLCR |= 0x0f;   //HPLL=6MHz*82=492MHz
    HPLL2CR &= ~0x60;   //高速外设时钟选择 HPLL/2
    HPLLCR |= 0x80;   //使能HPLL

    CLKDIV = 2;         //系统时钟=主时钟源/2 = HPLL/2/2 = 120MHz
    CLKSEL = 0x04;      //选择HPLL/2作为主时钟源
#endif

//    P5M0 |= 0x10; P5M1 &= ~0x10;//设置P5.4口为推挽输出
//    P5SR &= ~0x10;            //设置P5.4口为快速模式
//    HIRCCR |= 0x10;             //输出系统时钟
//    MCLKOCR = 10;               //系统时钟 10 分频到P5.4
}

//========================================================================
// 函数: 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(19200);          //设置波特率
    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;   //开始接收数据
      }
    }
    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 现场恢复
}

/********************* IO中断函数 *********************/
void IOINT_Config(void)
{
    //PnIM2,PnIM1,PnIM0000:下降沿中断; 001:上升沿中断; 010:低电平中断; 011:高电平中断; 100:边沿中断
    P8IM0 = 0x10;   //P8.4 上升沿中断
    P8IM1 = 0x00;
    P8IM2 = 0x00;
//    P8INTE = 0x10; //使能 P8.4 口上升沿中断
//    P8WKUE = 0xff; //使能 P8 口中断唤醒
}

void P8INT_ISR() interrupt P8INT_VECTOR
{
    u8 intf;

    intf = P8INTF; //P8 口中断

    if (intf & 0x10)
    {
      FallingCnt++;
      if(FallingCnt == 1)         //第1个上升沿:间隔场结束
      {
            TL0 = 0x00;   //设置定时初始值
            TH0 = 0x00;   //设置定时初始值
            T0Cnt = 0;
      }
      else if(FallingCnt == 2)    //第2个上升沿:同步场 bit0 开始
      {
            TR0 = 1;      //定时器0开始计时
      }
      else                        //第3个上升沿:同步场 bit2 开始
      {
            TR0 = 0;      //定时器0停止计时
            T0Cnt += ((u16)(TH0<<8) + TL0);
            T0Cnt >>= 5;    //DL = T0Cnt / 16 / 2 (采集2bit时间,所以要再除2)

            bDetFlag = 1;
            P8INTE = 0x00;//关闭 P8.4 口中断
            FallingCnt = 0;
      }
    }
    P8INTF = 0x00;
}

void Timer0_Init(void)
{
    AUXR |= 0x80;       //定时器时钟1T模式
    TMOD &= 0xF0;       //设置定时器模式
    TL0 = 0x00;         //设置定时初始值
    TH0 = 0x00;         //设置定时初始值
    TF0 = 0;            //清除TF0标志
//    TR0 = 1;            //定时器0开始计时
}

void DetStart(void)
{
    P8INTE = 0x10;          //使能 P8.4 口边沿中断
}

/******************** 串口打印函数 ********************/
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;
}





页: [1]
查看完整版本: 45.2-LIN1-LIN2主从收发测试-软件实现自动波特率,STC32G144K246实验箱演示程序