本帖最后由 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定时器作为时钟节拍。
每一层都使函数指针
// 函数指针变量,保存任务调度的函数地址
void (*usartTakeFunCb)(uint8_t *data,uint16_t datalen);
/**
***********************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] 注册任务调度回调函数
* @param pFunc, 传入回调函数地址
* [url=home.php?mod=space&uid=266161]@return[/url]
***********************************************************
*/
void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen))
{
usartTakeFunCb = pFunc;
}
应用层:实现的串口收发(演示)
发送接收缓冲区大小:2048
单次接收最大量:256
串口接收:DMA+空闲中断+双指针+双环形缓冲区
串口发送:DMA+发送中断+双指针+双环形缓冲区
#define UARTx_RX_SIZE 2048 //接收缓冲区长度
#define UARTx_TX_SIZE 2048 //发送缓冲区长度
#define UARTx_RX_MAX 256 //单次接收最大量
#define UARTx_TX_MAX 256 //单次接收最大量
#define SE_PTR_NUM 10 //se指针对结构体数组长度
typedef struct{
uint8_t *start; //start用于标记起始位置
uint8_t *end; //end用于标记结束位置
}LCB; //se 指针对结构体
typedef struct{
uint16_t RxCounter; //累计接收数据量
uint16_t TxCounter;
uint16_t TxState;
LCB RxLocation[SE_PTR_NUM]; //se指针对结构体数组
LCB *RxInPtr; //IN指针用于标记接收数据
LCB *RxOutPtr; //OUT指针用于提取接收的数据
LCB *RxEndPtr; ////IN和OUT指针的结尾标志
LCB TxLocation[SE_PTR_NUM]; //se指针对结构体数组
LCB *TxInPtr; //IN指针用于标记发送数据
LCB *TxOutPtr; //OUT指针用于提取发送的数据
LCB *TxEndPtr; ////IN和OUT指针的结尾标志
USART_InitTypeDef usart;
DMA_InitTypeDef dmatx;
DMA_InitTypeDef dmarx;
}Usartx_Control_Block;
extern uint8_t Usart1_RxBuffer[UARTx_RX_SIZE]; //串口1接收缓冲区
extern uint8_t Usart1_TxBuffer[UARTx_TX_SIZE]; //串口1发送缓冲区
extern Usartx_Control_Block usart1; //串口控制结构体
串口驱动层接收:
void USART1_IRQHandler(void)
{
//发送中断
if(USART_GetITStatus(USART1,USART_IT_TC) != RESET)
{
USART_ClearITPendingBit(USART1,USART_IT_TC);
}
//空闲中断
if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
{
USART1->SR; //清中断
USART1->DR; //清中断
usart1.RxCounter +=((UARTx_RX_MAX+1)- DMA_GetCurrDataCounter(DMA2_Stream2));
usart1.RxInPtr->end = &Usart1_RxBuffer[usart1.RxCounter - 1];
usart1.RxInPtr++;
if(usart1.RxInPtr == usart1.RxEndPtr)
{
usart1.RxInPtr = &usart1.RxLocation[0];
}
if(UARTx_RX_SIZE - usart1.RxCounter < UARTx_RX_MAX){
usart1.RxInPtr->start = Usart1_RxBuffer;
usart1.RxCounter = 0;
}else{
usart1.RxInPtr->start = &Usart1_RxBuffer[usart1.RxCounter]; //标记接位置
}
DMA_Cmd(DMA2_Stream2, DISABLE); //关闭DMA
DMA_SetCurrDataCounter(DMA2_Stream2, UARTx_RX_MAX+1);
DMA2_Stream2->M0AR = (uint32_t)usart1.RxInPtr->start;
DMA_Cmd(DMA2_Stream2, ENABLE); //打开DMA
}
}
串口驱动层发送:
void Usart1_Txdata(uint8_t *tdata,uint16_t datalen)
{
if((UARTx_TX_SIZE - usart1.TxCounter) >= datalen) //发送空间大于等于发数据
{
usart1.TxInPtr ->start = &Usart1_TxBuffer[usart1.TxCounter];
}else
{
usart1.TxCounter = 0; //发送空间小于发送数据,清0
usart1.TxInPtr->start = Usart1_TxBuffer;
}
memcpy(usart1.TxInPtr ->start,tdata,datalen); //数据拷贝
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA2_Stream7,datalen); //设置数据传输长度
usart1.TxCounter += datalen; //统计每次发送量
usart1.TxInPtr ->end = &Usart1_TxBuffer[usart1.TxCounter-1];//标记end位,为下次作准备
DMA2_Stream7->M0AR = (uint32_t)usart1.TxInPtr->start;
DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);
usart1.TxInPtr++;
if(usart1.TxInPtr == usart1.TxEndPtr){
usart1.TxInPtr = &usart1.TxLocation[0];
}
}
void Usart1_Event(uint8_t *data,uint16_t datalen)//任务事件入口
{
Usart1_Txdata(data,datalen);
}
void Usart1_Taskapp(void)
{
usart1TakeCb(Usart1_Event);//任务事件回函数入口地址
}
串口任务函数:
void usart1_take(void)
{
if(usart1.RxOutPtr != usart1.RxInPtr)
{
usartTakeFunCb(usart1.RxOutPtr->start,(usart1.RxOutPtr->end - usart1.RxOutPtr->start+1));
usart1.RxOutPtr++;
if(usart1.RxOutPtr == usart1.RxEndPtr)
{
usart1.RxOutPtr = &usart1.RxLocation[0];
}
}
if((usart1.TxOutPtr != usart1.TxInPtr) &&( usart1.TxState == 0))
{
usart1.TxState = 1;
DMA_Cmd(DMA2_Stream7,ENABLE);
usart1.TxOutPtr++;
if(usart1.TxOutPtr == usart1.TxEndPtr)
{
usart1.TxOutPtr = &usart1.TxLocation[0];
}
}
}
延时函数:
/**
***********************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] DWT初始化配置
* @param
* @return
* 使用JLINK和STLINK烧写程序,不能对DWT复位,要手动复位,用DAP烧写可以正常
***********************************************************
**/
void Delay_Init(void)
{
/* 关闭 TRC */
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
/* 打开 TRC */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* 关闭计数功能 */
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
/* 计数清零 */
DWT->CYCCNT = 0;
/* 打开计数功能 */
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
/**
***********************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] 微秒级延时函数
* @param nUs,最大延时时间( 2^32 / 内核主频 ) * 10^6 us
* [url=home.php?mod=space&uid=266161]@return[/url]
***********************************************************/
void Delay_us(uint32_t nus)
{
uint32_t tickStart = DWT->CYCCNT;
/* 转换为nUs对应的时钟跳动次数*/
nus *= (SystemCoreClock / 1000000);
/* 延时等待 */
while((DWT->CYCCNT - tickStart) <nus);
}
/**
***********************************************************
* @brief 毫秒级延时函数
* @param nMs,延时时间n毫秒
* [url=home.php?mod=space&uid=266161]@return[/url]
***********************************************************
**/
void Delay_ms(uint32_t nms)
{ uint32_t i;
for (i = 0; i < nms; i++)
{
Delay_us(1000);
}
}
//static __IO uint32_t TimingDelay;
///**
// * @brief 启动系统滴答定时器 SysTick
// * @param 无
// * @retval 无
// */
//void Delay_Init(void)
//{
// /* SystemFrequency / 1000 1ms中断一次
// * SystemFrequency / 100000 10us中断一次
// * SystemFrequency / 1000000 1us中断一次
// */
// if (SysTick_Config(SystemCoreClock / 1000000))
// {
// /* Capture error */
// while (1);
// }
//}
///**
// * @brief us延时程序,10us为一个单位
// * @param
// * [url=home.php?mod=space&uid=2817080]@ARG[/url] nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
// * @retval 无
// */
//void Delay_us(__IO uint32_t nTime)
//{
// TimingDelay = nTime;
// while(TimingDelay != 0);
//}
///**
// * @brief 获取节拍程序
// * @param 无
// * @retval 无
// * [url=home.php?mod=space&uid=93590]@Attention[/url] 在 SysTick 中断函数 SysTick_Handler()调用
// */
//void TimingDelay_Decrement(void)
//{
// if (TimingDelay != 0x00)
// {
// TimingDelay--;
// }
此部分内容已被设置为付费内容,您可以在支付 1 元 人民币后浏览本楼层全部付费内容。点击购买
本楼层付费信息已有6人购买 |