[STM32F4] STM32F4 LVGL(8.3)+FreeRTOS+软件分层设计

[复制链接]
2085|14
 楼主| zero949079783 发表于 2024-2-17 11:38 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2024-2-18 22:26 编辑

STM32F429 LVGL(8.3)+FreeRTOS(FreeRTOS V10.4.6)+软件分层设计
GD32F427 LVGL(8.3)+FreeRTOS(FreeRTOS V10.4.6)+软件分层设计

应用层:主要编写应用方面的,如功能实现等,实现的串口收发(演示),驱动层:各种外设软件层,应用层与驱动分离方式使用指针函数和回调函数分开
标准库层:仅STM32标准库或GD32库
中间层:LVGL,FreeRTOS,同理也软件与驱动分层。 使用systick定时器作为时钟节拍。
每一层都使函数指针

  1. // 函数指针变量,保存任务调度的函数地址
  2. void (*usartTakeFunCb)(uint8_t *data,uint16_t datalen);

  3. /**
  4. ***********************************************************
  5. * [url=home.php?mod=space&uid=247401]@brief[/url] 注册任务调度回调函数
  6. * @param pFunc, 传入回调函数地址
  7. * [url=home.php?mod=space&uid=266161]@return[/url]
  8. ***********************************************************
  9. */

  10. void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen))
  11. {
  12.         usartTakeFunCb = pFunc;
  13. }

应用层:实现的串口收发(演示)
发送接收缓冲区大小:2048
单次接收最大量:256
串口接收:DMA+空闲中断+双指针+双环形缓冲区
串口发送:DMA+发送中断+双指针+双环形缓冲区

  1. #define UARTx_RX_SIZE   2048                 //接收缓冲区长度
  2. #define UARTx_TX_SIZE   2048                //发送缓冲区长度
  3. #define UARTx_RX_MAX    256                        //单次接收最大量
  4. #define UARTx_TX_MAX    256                        //单次接收最大量
  5. #define SE_PTR_NUM      10                        //se指针对结构体数组长度


  6. typedef struct{
  7.     uint8_t *start;                                         //start用于标记起始位置                                                                        
  8.     uint8_t *end;                                        //end用于标记结束位置
  9. }LCB;                        //se 指针对结构体

  10. typedef struct{
  11.         
  12.         
  13.         uint16_t RxCounter;        //累计接收数据量
  14.         uint16_t TxCounter;
  15.         uint16_t TxState;
  16.         LCB RxLocation[SE_PTR_NUM];        //se指针对结构体数组
  17.         LCB *RxInPtr;                        //IN指针用于标记接收数据
  18.         LCB *RxOutPtr;                        //OUT指针用于提取接收的数据
  19.         LCB *RxEndPtr;                        ////IN和OUT指针的结尾标志
  20.         
  21.         LCB TxLocation[SE_PTR_NUM];        //se指针对结构体数组
  22.         LCB *TxInPtr;                        //IN指针用于标记发送数据
  23.         LCB *TxOutPtr;                        //OUT指针用于提取发送的数据
  24.         LCB *TxEndPtr;                        ////IN和OUT指针的结尾标志

  25.         USART_InitTypeDef usart;
  26.         DMA_InitTypeDef  dmatx;        
  27.         DMA_InitTypeDef  dmarx;
  28.         
  29. }Usartx_Control_Block;

  30. extern uint8_t Usart1_RxBuffer[UARTx_RX_SIZE];      //串口1接收缓冲区
  31. extern uint8_t Usart1_TxBuffer[UARTx_TX_SIZE];      //串口1发送缓冲区
  32. extern Usartx_Control_Block  usart1;                                                               //串口控制结构体

串口驱动层接收:
  1. void USART1_IRQHandler(void)
  2. {
  3.         //发送中断
  4.         if(USART_GetITStatus(USART1,USART_IT_TC) != RESET)
  5.         {
  6.                 USART_ClearITPendingBit(USART1,USART_IT_TC);

  7.         }                                
  8.         //空闲中断
  9.         if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
  10.         {               
  11.                 USART1->SR;                       //清中断
  12.                 USART1->DR;                       //清中断               
  13.                 usart1.RxCounter +=((UARTx_RX_MAX+1)- DMA_GetCurrDataCounter(DMA2_Stream2));
  14.                 usart1.RxInPtr->end = &Usart1_RxBuffer[usart1.RxCounter - 1];
  15.                
  16.                 usart1.RxInPtr++;
  17.                 if(usart1.RxInPtr == usart1.RxEndPtr)
  18.                 {
  19.                         usart1.RxInPtr = &usart1.RxLocation[0];
  20.                 }
  21.                 if(UARTx_RX_SIZE - usart1.RxCounter < UARTx_RX_MAX){
  22.                         usart1.RxInPtr->start = Usart1_RxBuffer;
  23.                         usart1.RxCounter = 0;                                                               
  24.                 }else{
  25.                         usart1.RxInPtr->start = &Usart1_RxBuffer[usart1.RxCounter];         //标记接位置
  26.                 }               
  27.                
  28.                 DMA_Cmd(DMA2_Stream2, DISABLE);     //关闭DMA
  29.                 DMA_SetCurrDataCounter(DMA2_Stream2, UARTx_RX_MAX+1);
  30.                 DMA2_Stream2->M0AR = (uint32_t)usart1.RxInPtr->start;
  31.                 DMA_Cmd(DMA2_Stream2, ENABLE);     //打开DMA                        
  32.         }        
  33. }



串口驱动层发送:
  1. void Usart1_Txdata(uint8_t *tdata,uint16_t datalen)
  2. {
  3.         
  4. if((UARTx_TX_SIZE - usart1.TxCounter) >= datalen) //发送空间大于等于发数据
  5.         {
  6.                 usart1.TxInPtr ->start = &Usart1_TxBuffer[usart1.TxCounter];
  7.         }else
  8.         {
  9.                 usart1.TxCounter = 0;        //发送空间小于发送数据,清0
  10.                 usart1.TxInPtr->start = Usart1_TxBuffer;
  11.         }
  12.         
  13.         memcpy(usart1.TxInPtr ->start,tdata,datalen);        //数据拷贝
  14.         while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);        //确保DMA可以被设置
  15.         DMA_SetCurrDataCounter(DMA2_Stream7,datalen);                        //设置数据传输长度
  16.         
  17.         usart1.TxCounter += datalen;        //统计每次发送量
  18.         usart1.TxInPtr ->end = &Usart1_TxBuffer[usart1.TxCounter-1];//标记end位,为下次作准备
  19.         DMA2_Stream7->M0AR  = (uint32_t)usart1.TxInPtr->start;
  20.         DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);        
  21.         usart1.TxInPtr++;
  22.         if(usart1.TxInPtr == usart1.TxEndPtr){
  23.                 usart1.TxInPtr = &usart1.TxLocation[0];               
  24.         }
  25. }


  1. void Usart1_Event(uint8_t *data,uint16_t datalen)//任务事件入口
  2. {
  3.         Usart1_Txdata(data,datalen);
  4. }

  5. void Usart1_Taskapp(void)
  6. {
  7.         usart1TakeCb(Usart1_Event);//任务事件回函数入口地址
  8. }


串口任务函数:
  1. void usart1_take(void)
  2. {
  3.         if(usart1.RxOutPtr != usart1.RxInPtr)
  4.         {
  5.                 usartTakeFunCb(usart1.RxOutPtr->start,(usart1.RxOutPtr->end - usart1.RxOutPtr->start+1));
  6.                
  7.                 usart1.RxOutPtr++;
  8.                 if(usart1.RxOutPtr == usart1.RxEndPtr)
  9.                 {
  10.                         usart1.RxOutPtr = &usart1.RxLocation[0];
  11.                 }
  12.         }

  13.         if((usart1.TxOutPtr != usart1.TxInPtr) &&( usart1.TxState == 0))
  14.         {
  15.                 usart1.TxState = 1;

  16.                 DMA_Cmd(DMA2_Stream7,ENABLE);        

  17.                 usart1.TxOutPtr++;
  18.                 if(usart1.TxOutPtr == usart1.TxEndPtr)
  19.                 {
  20.                         usart1.TxOutPtr = &usart1.TxLocation[0];
  21.                 }
  22.                
  23.         }        
  24. }
延时函数:
  1. /**
  2. ***********************************************************
  3. * [url=home.php?mod=space&uid=247401]@brief[/url] DWT初始化配置
  4. * @param
  5. * @return
  6. *  使用JLINK和STLINK烧写程序,不能对DWT复位,要手动复位,用DAP烧写可以正常
  7. ***********************************************************
  8. **/
  9. void Delay_Init(void)
  10. {
  11.         /* 关闭 TRC */
  12.         CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
  13.         /* 打开 TRC */
  14.         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;        
  15.         /* 关闭计数功能 */
  16.         DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
  17.         /* 计数清零 */
  18.         DWT->CYCCNT = 0;        
  19.         /* 打开计数功能 */
  20.         DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;        
  21. }
  22. /**
  23. ***********************************************************
  24. * [url=home.php?mod=space&uid=247401]@brief[/url] 微秒级延时函数
  25. * @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us
  26. * [url=home.php?mod=space&uid=266161]@return[/url]
  27. ***********************************************************/
  28. void Delay_us(uint32_t nus)
  29. {               
  30.         uint32_t tickStart = DWT->CYCCNT;
  31.         
  32.         /* 转换为nUs对应的时钟跳动次数*/
  33.         nus *= (SystemCoreClock / 1000000);
  34.         
  35.         /* 延时等待 */
  36.         while((DWT->CYCCNT - tickStart) <nus);
  37.         
  38. }

  39. /**
  40. ***********************************************************
  41. * @brief 毫秒级延时函数
  42. * @param nMs,延时时间n毫秒
  43. * [url=home.php?mod=space&uid=266161]@return[/url]
  44. ***********************************************************
  45. **/
  46. void Delay_ms(uint32_t nms)
  47. {        uint32_t i;
  48.         for (i = 0; i < nms; i++)
  49.         {
  50.                 Delay_us(1000);
  51.         }
  52. }

  53. //static __IO uint32_t TimingDelay;

  54. ///**
  55. //  * @brief  启动系统滴答定时器 SysTick
  56. //  * @param  无
  57. //  * @retval 无
  58. //  */
  59. //void Delay_Init(void)
  60. //{
  61. //        /* SystemFrequency / 1000    1ms中断一次
  62. //         * SystemFrequency / 100000         10us中断一次
  63. //         * SystemFrequency / 1000000 1us中断一次
  64. //         */
  65. //        if (SysTick_Config(SystemCoreClock / 1000000))
  66. //        {
  67. //                /* Capture error */
  68. //                while (1);
  69. //        }
  70. //}

  71. ///**
  72. //  * @brief   us延时程序,10us为一个单位
  73. //  * @param  
  74. //  *                [url=home.php?mod=space&uid=2817080]@ARG[/url] nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
  75. //  * @retval  无
  76. //  */
  77. //void Delay_us(__IO uint32_t nTime)
  78. //{
  79. //        TimingDelay = nTime;        

  80. //        while(TimingDelay != 0);
  81. //}

  82. ///**
  83. //  * @brief  获取节拍程序
  84. //  * @param  无
  85. //  * @retval 无
  86. //  * [url=home.php?mod=space&uid=93590]@Attention[/url]  在 SysTick 中断函数 SysTick_Handler()调用
  87. //  */
  88. //void TimingDelay_Decrement(void)
  89. //{
  90. //        if (TimingDelay != 0x00)
  91. //        {
  92. //                TimingDelay--;
  93. //        }



[payamount]1.00[/payamount]
[pay]STM32F4
链接:https://pan.baidu.com/s/1kPfiWYPSW1u2hz2pub1HDA?pwd=sqba
提取码:sqba

GD32F4
链接:https://pan.baidu.com/s/1OdzGtWxEz-U8JPs8iQaJKg?pwd=5rr3
提取码:5rr3


[/pay]








   
tpgf 发表于 2024-4-2 15:06 | 显示全部楼层
用户需要对中间层的驱动进行处理吗
xiaoqizi 发表于 2024-4-2 15:45 | 显示全部楼层
发送缓冲区的大小可以动态进行调整吗
 楼主| zero949079783 发表于 2024-4-2 19:19 | 显示全部楼层
xiaoqizi 发表于 2024-4-2 15:45
发送缓冲区的大小可以动态进行调整吗

固定好了,一包数据最大是256,缓冲区2048,觉得上,可自调整
 楼主| zero949079783 发表于 2024-4-2 19:21 | 显示全部楼层
tpgf 发表于 2024-4-2 15:06
用户需要对中间层的驱动进行处理吗

中间层主要是做一些逻辑处理的,把接口做好了,就放在应用层使用的。这个只是框架
caigang13 发表于 2024-4-2 20:36 来自手机 | 显示全部楼层
我晕,还要付费才能看。
wowu 发表于 2024-4-2 21:42 | 显示全部楼层
无论是什么应用都是这样分层的吗
wakayi 发表于 2024-4-2 22:14 | 显示全部楼层
这两种单片机的设计理念应该都是相同的
 楼主| zero949079783 发表于 2024-4-2 22:22 | 显示全部楼层
wakayi 发表于 2024-4-2 22:14
这两种单片机的设计理念应该都是相同的

相同的,只是不同MCU
renzheshengui 发表于 2024-4-2 22:46 | 显示全部楼层
感觉这种分层方式有点像是以太网的分层
paotangsan 发表于 2024-4-2 23:18 | 显示全部楼层
软件的分层是依据什么来划分的呢
chenjun89 发表于 2024-4-3 08:08 来自手机 | 显示全部楼层
纳尼,还得付费才能看。
earlmax 发表于 2024-4-7 10:21 | 显示全部楼层
LVGL 是一个开源的嵌入式GUI库,适用于微控制器和处理器。
它轻量级、开源、易于使用,支持多平台,包括 STM32。
wangdezhi 发表于 2024-4-7 22:42 | 显示全部楼层
FreeRTOS 是一个开源的实时操作系统(RTOS),它为嵌入式系统提供了任务调度、时间管理、内存管理等功能。
EmmaTT 发表于 2024-4-8 15:26 来自手机 | 显示全部楼层
还有付费可见的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

91

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部