完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
这次学习的是官方例程中的Asynchronous Scheduling,emm因为我也是一边学习一边记录,所以现在也没办法解释整个框架的结构啥的。后面我会一步一步看,慢慢分析的。
例子官网链接:官网例程链接 模型程序链接:模型+程序 一、主要功能 定时器或ePWM模块用于配置定时器中断。定时器中断是根据定时器周期触发的,当收到消息时会触发eCAN消息接收中断。硬件中断块(图中的蓝色模块)触发定时器中断以及eCAN消息接收中断的中断服务程序(ISR)。ISR依次调用连接到硬件中断模块输出端口的功能调用子系统。 前两个子系统的输出是自由运行的计数器。计数器的总和用于控制F2812的PWMB或F2808 / F28335的ePWM2的占空比。PWM波形占空比从0到100%线性增加。 第三个子系统包含一个eCAN接收模块,其消息输出控制PWM模块的占空比(F2812为PWMA或F2808 / F28335为ePWM1)。占空比从0到100%不等,因为从eCAN发送模块接收到eCAN消息。 注意:启用eCAN_A 的回环模式(自发自收)可以在内部连接eCAN_A发送器和接收器,以避免在发送器和接收器之间进行外部连接。要禁用eCAN_A 的回环模式,发送器和接收器必须在外部连接在一起____________以上部分来自官方说明 因为CAN的知识有点遗忘,这里补一下课。 二、CAN总线 帧种类:1.数据帧2.遥控帧3.错误帧4.过载帧5.间隔帧 1.数据帧:用于发送单元向接收单元传送数据的帧。 2.遥控帧:用于接收单元向具有相同ID的发送单元请求数据的帧。 3.错误帧:用于当检测出错误时,向其他单元通知错误的帧。 4.过载帧:用于接收单元通知其尚未做好接收准备的帧。 5.间隔帧:用于数据帧及遥控帧与前面的帧分离开来的帧。 其中,数据帧与遥控帧有标准格式(11个标识符[ID])与扩展格式(29个标识符[ID])两种格式。因为实际中使用的数据帧过程最多,这里着重看看数据帧。 数据段一共由七个段组成:①帧起始②仲裁段③控制段④数据段(最多传送8个字节)⑤CRC段⑥ACK段⑦帧结束 **帧起始:**一个显性电平表示帧起始 仲裁段: I、标准格式:11位基本ID+RTR(远程请求位[0:数据帧,1:远程帧]) II、扩展格式:11位基本ID+SRR(替代远程请求位[设置为1])+IDE(标识符选择位[0:标准标识符,1:扩展标识符])+18位扩展ID +RTR(远程请求位[0:数据帧,1:远程帧]) 控制段: I、标准格式:IDE(标识符选择位[0:标准标识符,1:扩展标识符])+r0(保留位)+DLC(数据长度/字节) II、扩展格式:r0(保留位)+r1(保留位)+DLC(数据长度/字节) **数据段:**8个字节,两种帧格式完全一样。 **CRC段:**15个CRC+一位CRC界定符 **ACK段:**ACK槽+ACK界定符(发送单元:发送2个隐性位,接收单元:接收正确消息-ACK槽发送显性) **帧结束:**七个位隐性位组成 仲裁手段:1.总线空闲时,最先发送的单元具有优先级2.多个单元同时发送时,连续输出显性电平(逻辑0)多的单元(从ID位进行比较,直到RTR与SRR等位),具有最高优先级。 波特率设置:1位分为4个段(同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2)),每个段分为若干个Tq,这称为位时序。位时间=1/波特率。
1.操作模式
i、上图可以看出测试模式的进入寄存器位设置,其中CAN Control register 中的Test bit必须设置为1,才能使能CAN_TEST模式。
2.时钟来源:i、外部时钟。ii、系统时钟。iii、GPIO辅助时钟 3.中断功能:通过设置IE0与IE1可以使能CAN0INT与CAN1INT。CAN模块可以响应三种中断:i、消息中断。ii、状态改变中断。iii、错误中断。中断源通过Int0lD/Int1lD进行区分。消息中断的优先级与消息邮箱编号有关,1有最高优先级。中断需要在CAN_GLB_INT_EN register 中启用,处理中断时,必须先清除消息或者状态改变标志,然后进行应答。(via CAN_GLB_INT_CLR and PIEACK ) 消息中断:IntPND, TxIE and RxIE (Interrupt Multiplexer register )可以触发CAN0INT与CAN1INT 状态改变中断:RxOk, TxOk, and LEC (Error and Status register )可以触发CAN0INT[需要使能SIE位] 错误中断:PER, BOff and EWarn 可以触发CAN0INT[需要使能EIE位] 四、生成程序 程序框架相对于第一个程序没有很大的变化, #include "c2807x_2837xx_asyncscheduling_ert.h" #include "rtwtypes.h" volatile int IsrOverrun = 0; static boolean_T OverrunFlag = 0; void rt_OneStep(void) { /* Check for overrun. Protect OverrunFlag against preemption */ if (OverrunFlag++) { IsrOverrun = 1; OverrunFlag--; return; } enableTimer0Interrupt(); c2807x_2837xx_asyncscheduling_ert_step(); /* Get model outputs here */ disableTimer0Interrupt(); OverrunFlag--; } volatile boolean_T stopRequested = false; volatile boolean_T runModel = false; int main(void) { float modelBaseRate = 0.001; float systemClock = 200; /* Initialize variables */ stopRequested = false; runModel = false; c2000_flash_init(); init_board(); #ifdef MW_EXEC_PROFILER_ON config_profilerTimer(); #endif ; rtmSetErrorStatus(c2807x_2837xx_asyncschedulin_M, 0); c2807x_2837xx_asyncscheduling_ert_initialize(); configureTimer0(modelBaseRate, systemClock); runModel = rtmGetErrorStatus(c2807x_2837xx_asyncschedulin_M) == (NULL); enableTimer0Interrupt(); enable_interrupts(); //开启ePWM3/4以及CAN接收中断 globalInterruptEnable(); while (runModel) { stopRequested = !( rtmGetErrorStatus(c2807x_2837xx_asyncschedulin_M) == (NULL)); } /* Disable rt_OneStep() here */ /* Terminate model */ c2807x_2837xx_asyncscheduling_ert_terminate(); globalInterruptDisable(); return 0; } /* * File trailer for generated code. * * [EOF] */ 仍旧是在主函数完成硬件的初始化:c2807x_2837xx_asyncscheduling_ert_initialize(), 设置Timer0作为步长的解算器:configureTimer0(modelBaseRate, systemClock), 每经过一次步长进入Timer0中断函数进行执行:rt_OneStep() **c2807x_2837xx_asyncscheduling_ert_initialize()**中完成有关外设的初始化: 1.CAN接收的初始化(1.使能接收中断2.使能mailbox1作为接收邮箱) tCANMsgObject sRXCANMessage; unsigned char ucRXMsgData[8]= { 0, 0, 0, 0, 0, 0, 0, 0 }; sRXCANMessage.ui32MsgID = 455; // CAN message ID sRXCANMessage.ui32MsgIDMask = 0; // no mask needed for TX sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE; sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);// size of message is 4 sRXCANMessage.pucMsgData = ucRXMsgData;// ptr to message content // Setup the message object being used to receive messages CANMessageSet(CANA_BASE, 1, &sRXCANMessage, MSG_OBJ_TYPE_RX); 2.ePWM1模块初始化接收eCAN传送来的信息改变占空比。 3.ePWM2模块初始化接收ePWM3和ePWM4送来的信息改变占空比。 4.存储有关的参数进入系统结构体中,参数都是模块的参数。 Timer0中断函数中: 1.开启TIimer0中断(PIE1.7)、开启ePWM3、ePWM4中断。(PIE3.3、PIE3.4) 2.执行**c2807x_2837xx_asyncscheduling_ert_step()**函数: 1)因为程序中存在一个缓冲模块,这里通过一个数组进行缓存。Rate Transfer模块左侧是100k每秒改变一次的数值,右侧的add模块为1K做一次加法。程序中采用了一个数组进行缓存数据。 2)将两个缓存的模块输出直接进行相加后,赋值给ePWM2的CMPA模块 3)eCAN传送的数据的完成自加1后返回(为下一次传送+1数据做准备) 还有三个中断函数内容没有看,分别是ePWM3/4中断和eCANA接收中断:(这三个中断服务函数都在MW_c28xx_csl .c文件中)。 ePWM3的中断函数:**EPWM3_INT_isr()**函数: void isr_int3pie3_task_fcn(void) { /* Call the system: { /* S-Function (c28xisr_c2000): ' /* Output and update for function-call system: ' { uint16_T rtb_FixPtSum1; /* UnitDelay: ' c2807x_2837xx_asyncscheduling_B.Output_f = c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g; /* Sum: ' * Constant: ' */ rtb_FixPtSum1 = (c2807x_2837xx_asyncscheduling_B.Output_f + c2807x_2837xx_asyncscheduling_P.FixPtConstant_Value) & 8191U; //8191=0x1FFF; /* Switch: ' if (rtb_FixPtSum1 > c2807x_2837xx_asyncscheduling_P.WrapToZero_Threshold) { /* Update for UnitDelay: ' * Constant: ' */ c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g = c2807x_2837xx_asyncscheduling_P.Constant_Value; } else { /* Update for UnitDelay: ' c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g = rtb_FixPtSum1; } /* End of Switch: ' } /* End of Outputs for S-Function (c28xisr_c2000): ' /* Update for RateTransition: ' c2807x_2837xx_asyncschedulin_DW.RateTransition_Buffer[c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx == 0] = c2807x_2837xx_asyncscheduling_B.Output_f; c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx = (c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx == 0);//让缓冲地址在0-1之间循环 } } 生成的每个数字每进入一次中断自加1(0-8191之间循环),然后更新缓冲模块。 ePWM4的中断函数:**EPWM4_INT_isr()**函数:与ePWM3生成函数雷同,但是运行范围在0-16383之间。 void isr_int3pie4_task_fcn(void) { /* Call the system: { /* S-Function (c28xisr_c2000): ' /* Output and update for function-call system: ' { uint16_T rtb_FixPtSum1; /* UnitDelay: ' c2807x_2837xx_asyncscheduling_B.Output_i = c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n; /* Sum: ' * Constant: ' */ rtb_FixPtSum1 = (c2807x_2837xx_asyncscheduling_B.Output_i + c2807x_2837xx_asyncscheduling_P.FixPtConstant_Value_i) & 16383U; /* Switch: ' if (rtb_FixPtSum1 > c2807x_2837xx_asyncscheduling_P.WrapToZero_Threshold_e) { /* Update for UnitDelay: ' * Constant: ' */ c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n = c2807x_2837xx_asyncscheduling_P.Constant_Value_p; } else { /* Update for UnitDelay: ' c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n = rtb_FixPtSum1; } /* End of Switch: ' } /* End of Outputs for S-Function (c28xisr_c2000): ' /* Update for RateTransition: ' c2807x_2837xx_asyncschedulin_DW.RateTransition1_Buffer[c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx == 0] = c2807x_2837xx_asyncscheduling_B.Output_i; c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx = (c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx == 0); } } CAN接收中断函数:CANA0_INT_isr(): void isr_int9pie5_task_fcn(void) { /* Call the system: { /* S-Function (c28xisr_c2000): ' /* Output and update for function-call system: ' /* S-Function (c280xcanrcv): ' { tCANMsgObject sRXCANMessage; unsigned char ucRXMsgData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; sRXCANMessage.ui32MsgID = 455; // CAN message ID sRXCANMessage.ui32MsgIDMask = 0; // no mask needed for TX sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE; sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);// size of message sRXCANMessage.pucMsgData = ucRXMsgData;// ptr to message content // Get the receive message CANMessageGet(CANA_BASE, 1, &sRXCANMessage, false); if (sRXCANMessage.ui32MsgLen > 0) { c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[0] = ucRXMsgData[0] | (ucRXMsgData[1] << 8); c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[1] = ucRXMsgData[2] | (ucRXMsgData[3] << 8); c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[2] = ucRXMsgData[4] | (ucRXMsgData[5] << 8); c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[3] = ucRXMsgData[6] | (ucRXMsgData[7] << 8); /* -- Call CAN RX Fcn-Call_0 -- */ } } /* S-Function (c2802xpwm): ' /*-- Update CMPA value for ePWM1 --*/ { EPwm1Regs.CMPA.bit.CMPA = (uint16_T) (c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[0]); } /* End of Outputs for S-Function (c28xisr_c2000): ' } } CAN接收中断实现了读取CAN的数据内容,然后进行拼接(CAN接收是按8位进行接收,CMPA是16位寄存器,所以两个8位数据进行拼接变成Uint16)赋给CMPA。 五、总结 可以发现,Simulink生成的函数,框架结构非常严格,可能这就是代码生成的特点把。基本上框架搭好之后,对每个部分重新填充便是一个新的功能函数,代码移植效率也很高。但是机器还是有缺点的,程序可读性没有那么高。再就是报错的时候一脸懵逼,代码生成的报错都是一堆一堆,有点找不到头绪。这两个例子大致是明白了代码工作的情况,下一步准备再多看几个例子多熟悉一下各个库器件。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1379 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1369 浏览 1 评论
795 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
569 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1412 浏览 2 评论
1762浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
492浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
426浏览 3评论
416浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
393浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-10-1 18:16 , Processed in 0.807247 second(s), Total 49, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号