今日初步认识与配置使用Lin通信SCI模式完整的发送与中断接收功能,用结构体寄存器的方式编程
文章提供完整工程下载、测试效果图
我的单片机平台是这个:
目录
LIN-SCI接收中断:
手册3459页提到了SCI的接收中断
手册还提到了INT0 与INT1 这俩个LIN通信提供的中断源可以链接各种类型的中断:
在代码中,我将RX中断连接到了INT0上:
其次,INT0 与 INT1 还需要开启 PIE总中断:
LIN-SCI初始化:
接收中断打开了,但注释了发送中断
如果你启用发送中断,需要自己链接到中断服务函数并清理对应标志位!
void Init_LINA_SCIMode(void) { //uint32_t i; // 链接中断服务函数 与 初始化引脚 EALLOW; PieVectTable.LINA_0_INT = &level0ISR; //RX_INT PieVectTable.LINA_1_INT = &level1ISR; //TX_INT PieCtrlRegs.PIEIER8.bit.INTx9 = 1; //8.9 PieCtrlRegs.PIEIER8.bit.INTx10 = 1; //8.10 IER |= M_INT8; GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0; //Enable pull-up GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0; //GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; //Asynch input (LIN_SCI RX) GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 2; // Configure GPIO55 for RX operation GpioCtrlRegs.GPBGMUX2.bit.GPIO55 = 2; GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 2; // Configure GPIO54 for TX operation GpioCtrlRegs.GPBGMUX2.bit.GPIO54 = 2; GpioCtrlRegs.GPBDIR.bit.GPIO54 = 1; // 输出(TX) GpioCtrlRegs.GPBDIR.bit.GPIO55 = 0; // 输入(RX) //此位确定INT1中断行是否产生对PIE的中断 LinaRegs.LIN_GLB_INT_EN.bit.GLBINT0_EN = 1; LinaRegs.LIN_GLB_INT_EN.bit.GLBINT1_EN = 1; LinaRegs.SCISETINTLVL.bit.SETRXINTOVO = 0; // 0:中断映射到INT0线 1:中断映射到INT1线 //重载 以启用 LIN模块 LinaRegs.SCIGCR0.bit.RESET = 1; LinaRegs.SCIGCR1.bit.SWnRST = 0; //引脚控制寄存器 LinaRegs.SCIPIO0.bit.RXFUNC = 1; LinaRegs.SCIPIO0.bit.TXFUNC = 1; //SCI兼容模式引脚 LinaRegs.SCIPIO2.bit.RXIN = 1; LinaRegs.SCIPIO2.bit.TXIN = 1; //多缓冲区模式: LinaRegs.SCIGCR1.bit.MBUFMODE = 0; //是否使用RX/TX多缓冲器或使用单个寄存器RD0/TD0。 LinaRegs.SCIGCR1.bit.STOP = 0; //0:1位停止位 1:2位停止位 LinaRegs.SCIGCR1.bit.PARITYENA = 0; // 禁用奇偶校验 LinaRegs.SCIGCR1.bit.PARITY = 0; //0:奇校验 1::偶校验 (如果使能了奇偶校验) LinaRegs.SCIFORMAT.bit.CHAR = 7; //8位数据长度 //设定 波特率 115200 得到组合: P=39 M=11 U=0 ---> VCLK 默认 SYSCLK 2分频 // ClkCfgRegs.PERCLKDIVSEL.bit.LINACLKDIV = 4; // 预分频 VCLK = SYSCLK / 4 = 375 000 00 LinaRegs.BRSR.bit.M = 11; LinaRegs.BRSR.bit.SCI_LIN_PSH = (39 >> 8) & 0xff; LinaRegs.BRSR.bit.SCI_LIN_PSL = 39 & 0xff; LinaRegs.BRSR.bit.U = 0; LinaRegs.SCIGCR1.bit.CLK_COMMANDER = 1; //SCI兼容模式 LinaRegs.SCIGCR1.bit.TIMINGMODE = 1; //SCI异步操作,SCI模式必须设为1 // LinaRegs.SCIGCR1.bit.COMMMODE = 0;//0:SCI空闲线 1:SCI地址位 LinaRegs.SCIGCR1.bit.ADAPT = 0; //禁用自动波特率 LinaRegs.SCIGCR1.bit.CONT = 1; //使LIN在仿真断点处不会停止,直到LIN当前接收或传输完成 //使能收发 LinaRegs.SCIGCR1.bit.RXENA = 1; LinaRegs.SCIGCR1.bit.TXENA = 1; //使能中断 LinaRegs.SCISETINT.bit.SETRXINT = 1; //接收中断 //LinaRegs.SCISETINT.bit.SETTXINT = 1; //发送中断 //重启LIN模块 LinaRegs.SCIGCR1.bit.SWnRST = 1; EDIS; }
LIN的发送函数:
我写了三个发送函数,分别是单个字节发送,字符串发送,printf,
最后一个适合调试,用法如下:
void LIN_Transmit_Data_SCIMode(unsigned char Data) { LinaRegs.SCITD.bit.TD = Data; while (LinaRegs.SCIFLR.bit.TXRDY == 0) //等待发送完成 { //考虑添加超时逻辑 } // LinaRegs.SCIFLR.bit.TXEMPTY // LinaRegs.SCIFLR.bit.TXRDY } void LIN_Transmit_String_SCIMode(unsigned char *string) { int i; i = 0; while(string[i] != '\0') { LIN_Transmit_Data_SCIMode(string[i]); i++; } } // 自定义printf函数 void LIN_SCIMode_Printf(char *fmt,...) { unsigned char UsartPrintfBuf[128];//最大长度128 va_list ap; unsigned char *pStr = UsartPrintfBuf; va_start(ap, fmt); vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //格式化 va_end(ap); while(*pStr != 0 ) { LIN_Transmit_Data_SCIMode(*pStr++); //逐个字节发送 // 检查传输错误 } }
#include "Lin_1.h"
完整的LIN通信配置代码如下:
/* * Lin.c * * Created on: 2025年4月11日 * Author: 30313 */ #include "Lin_1.h" void Init_LINA_SCIMode(void) { //uint32_t i; // 链接中断服务函数 与 初始化引脚 EALLOW; PieVectTable.LINA_0_INT = &level0ISR; //RX_INT PieVectTable.LINA_1_INT = &level1ISR; //TX_INT PieCtrlRegs.PIEIER8.bit.INTx9 = 1; //8.9 PieCtrlRegs.PIEIER8.bit.INTx10 = 1; //8.10 IER |= M_INT8; GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0; //Enable pull-up GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0; //GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; //Asynch input (LIN_SCI RX) GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 2; // Configure GPIO55 for RX operation GpioCtrlRegs.GPBGMUX2.bit.GPIO55 = 2; GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 2; // Configure GPIO54 for TX operation GpioCtrlRegs.GPBGMUX2.bit.GPIO54 = 2; GpioCtrlRegs.GPBDIR.bit.GPIO54 = 1; // 输出(TX) GpioCtrlRegs.GPBDIR.bit.GPIO55 = 0; // 输入(RX) //重载 以启用 LIN模块 LinaRegs.SCIGCR0.bit.RESET = 1; LinaRegs.SCIGCR1.bit.SWnRST = 0; //引脚控制寄存器 LinaRegs.SCIPIO0.bit.RXFUNC = 1; LinaRegs.SCIPIO0.bit.TXFUNC = 1; //SCI兼容模式引脚 LinaRegs.SCIPIO2.bit.RXIN = 1; LinaRegs.SCIPIO2.bit.TXIN = 1; //多缓冲区模式: LinaRegs.SCIGCR1.bit.MBUFMODE = 0; //是否使用RX/TX多缓冲器或使用单个寄存器RD0/TD0。 LinaRegs.SCIGCR1.bit.STOP = 0; //0:1位停止位 1:2位停止位 LinaRegs.SCIGCR1.bit.PARITYENA = 0; // 禁用奇偶校验 LinaRegs.SCIGCR1.bit.PARITY = 0; //0:奇校验 1::偶校验 (如果使能了奇偶校验) LinaRegs.SCIFORMAT.bit.CHAR = 7; //8位数据长度 //设定 波特率 115200 得到组合: P=39 M=11 U=0 ---> VCLK 默认 SYSCLK 2分频 // ClkCfgRegs.PERCLKDIVSEL.bit.LINACLKDIV = 4; // 预分频 VCLK = SYSCLK / 4 = 375 000 00 LinaRegs.BRSR.bit.M = 11; LinaRegs.BRSR.bit.SCI_LIN_PSH = (39 >> 8) & 0xff; LinaRegs.BRSR.bit.SCI_LIN_PSL = 39 & 0xff; LinaRegs.BRSR.bit.U = 0; LinaRegs.SCIGCR1.bit.CLK_COMMANDER = 1; //SCI兼容模式 LinaRegs.SCIGCR1.bit.TIMINGMODE = 1; //SCI异步操作,SCI模式必须设为1 // LinaRegs.SCIGCR1.bit.COMMMODE = 0;//0:SCI空闲线 1:SCI地址位 LinaRegs.SCIGCR1.bit.ADAPT = 0; //禁用自动波特率 LinaRegs.SCIGCR1.bit.CONT = 1; //使LIN在仿真断点处不会停止,直到LIN当前接收或传输完成 //使能收发 LinaRegs.SCIGCR1.bit.RXENA = 1; LinaRegs.SCIGCR1.bit.TXENA = 1; //此位确定INT1中断行是否产生对PIE的中断 LinaRegs.LIN_GLB_INT_EN.bit.GLBINT0_EN = 1; LinaRegs.LIN_GLB_INT_EN.bit.GLBINT1_EN = 1; LinaRegs.SCISETINTLVL.bit.SETRXINTOVO = 0; // 0:中断映射到INT0线 1:中断映射到INT1线 //使能中断 LinaRegs.SCISETINT.bit.SETRXINT = 1; //接收中断 //LinaRegs.SCISETINT.bit.SETTXINT = 1; //发送中断 //重启LIN模块 LinaRegs.SCIGCR1.bit.SWnRST = 1; EDIS; } // 会有其余中断情况 会进这个函数 // 我只是连接了RX 中断 与 INT0 的关系 __interrupt void level0ISR(void) { unsigned char temp; static unsigned char i = 0;//记录进了几次中断,查看是否有除了RX中断的中断 i++; //如果接收中断 if(LinaRegs.SCIFLR.bit.RXRDY == 1) { temp = LinaRegs.SCIRD.bit.RD;//不读RXRDY不会清除,RXRDY写1才能清除 LIN_Transmit_Data_SCIMode(temp); } LinaRegs.LIN_GLB_INT_CLR.bit.INT0_FLG_CLR = 1;//清除中断 PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; //LinaRegs.SCICLEARINT.bit.CLRRXINT = 1;//关闭接收中断 //LinaRegs.SCISETINT.bit.SETRXINT = 1; //重新启用接收中断 } __interrupt void level1ISR(void) { } void LIN_Transmit_Data_SCIMode(unsigned char Data) { LinaRegs.SCITD.bit.TD = Data; while (LinaRegs.SCIFLR.bit.TXRDY == 0) //等待发送完成 { //考虑添加超时逻辑 } // LinaRegs.SCIFLR.bit.TXEMPTY // LinaRegs.SCIFLR.bit.TXRDY } void LIN_Transmit_String_SCIMode(unsigned char *string) { int i; i = 0; while(string[i] != '\0') { LIN_Transmit_Data_SCIMode(string[i]); i++; } } // 自定义printf函数 void LIN_SCIMode_Printf(char *fmt,...) { unsigned char UsartPrintfBuf[128];//最大长度1128 va_list ap; unsigned char *pStr = UsartPrintfBuf; va_start(ap, fmt); vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //格式化 va_end(ap); while(*pStr != 0 ) { LIN_Transmit_Data_SCIMode(*pStr++); //逐个字节发送 // 检查传输错误 } }
/* * Lin.h * * Created on: 2025年4月11日 * Author: 30313 */ #ifndef USER_LIN_1_H_ #define USER_LIN_1_H_ //#include "stdint.h" //uint32_t /uint16_t #include "f28x_project.h" #include "f28p55x_epwm_defines.h" #include "stdio.h" #include "stdarg.h" __interrupt void level0ISR(void); __interrupt void level1ISR(void); void Init_LINA_SCIMode(void); void LIN_Transmit_Data_SCIMode(unsigned char Data); void LIN_Transmit_String_SCIMode(unsigned char *string); void LIN_SCIMode_Printf(char *fmt,...); #endif /* USER_LIN_1_H_ */
测试效果图:
程序自动循环发送数据的同时,接收到消息会立刻回传:
完整工程下载:
https://download.youkuaiyun.com/download/qq_64257614/90631813