打开主菜单

谷雨文档中心 β

更改

NBDK-L4:LiteOS实验教程

添加9,829字节2019年4月4日 (四) 10:48
stm32l4xx_hal_conf.h
==== stm32l4xx_hal_conf.h ====
此文件位于“实验01-TFT显示屏\Src\User”路径中,主要用途是选择使能此例程使用到的HAL库文件。
 
使用STM32,大家默认需要打开的几个宏定义,芯片使能、flash、电源、时钟、NVIC,这个也很好理解,就是让芯片工作的必要几点。
 
此例程我们给大家展示的是TFT显示屏,所以我们需要请打开驱动TFT工作的SPI、GPIO以及DMA三个宏。其他的外设例程也需要使能对应的宏,这个大家有使用的疑问,可以查找一下基础实验中的相应的外设例程。<syntaxhighlight lang="c++" line="1" start="103">
// 使能的宏
#define HAL_MODULE_ENABLED // 芯片
#define HAL_FLASH_MODULE_ENABLED // Flash
#define HAL_PWR_MODULE_ENABLED // 电源
#define HAL_RCC_MODULE_ENABLED // 时钟
#define HAL_CORTEX_MODULE_ENABLED // NVIC
 
#define HAL_GPIO_MODULE_ENABLED // GPIO
#define HAL_DMA_MODULE_ENABLED // DMA
#define HAL_SPI_MODULE_ENABLED // SPI
</syntaxhighlight>
==== sys_init.c ====
时钟初始化函数,用于配置我们模块运行的系统时钟、AHB高性能总线时钟、APB外设总线时钟以及单个外设的时钟。
 
主要包含了三个部分的初始化配置。
# 内部或者外部振荡器选择,也就是选择时钟信号的来源,是内部振荡,还是外部晶振。
# 时钟配置,选择系统、AHB总线及APB总线的时钟来源。
# 外设时钟配置,选择外设时钟来源。
为了给大家比较全面的展示各个时钟,我们振荡器选择HSI(内部16MHz高频)、HSE(外部8MHz高频)以及LSE(外部32.768KHz低频)三个。选择HSE作为PLL(锁相回路)时钟源,配置PLLCLK为80MHz。配置系统时钟SYSCLK、AHB高性能总线、APB外设总线(APB1及APB2)为80MHz。另外我们还分别配置了ADC、UART以及I2C的外设时钟。
 
基础实验中的其他例程,大部分都是使用的相同的时钟配置函数,有特殊的时钟使用,将会在对应例程的源码详解中做针对性说明。<syntaxhighlight lang="c++" line="1" start="41">
//******************************************************************
// fn : SystemClock_Config
//
// brief : 系统时钟配置函数
//
// param : none
//
// return : none
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct; // 定义RCC内部/外部振荡器结构体
RCC_ClkInitTypeDef RCC_ClkInitStruct; // 定义RCC系统,AHB和APB总线时钟配置结构体
RCC_PeriphCLKInitTypeDef PeriphClkInit; // 定义RCC扩展时钟结构体
// 配置LSE驱动器功能为低驱动能力
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
 
// 初始化CPU,AHB和APB总线时钟
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE; // 设置需要配置的振荡器为HSI、HSE、LSE
// 配置HSE
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 激活HSE时钟(开发板外部为8MHz)
// 配置LSE
RCC_OscInitStruct.LSEState = RCC_LSE_ON; // 激活LSE时钟(32.768KHz,低驱动)
// 配置HSI
RCC_OscInitStruct.HSIState = RCC_HSI_ON; // 激活HSI时钟
RCC_OscInitStruct.HSICalibrationValue = 16; // 配置HSI为16MHz
// 配置PLL
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 打开PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // 选择HSE时钟作为PLL入口时钟源,8MHz
RCC_OscInitStruct.PLL.PLLM = 1; // 配置PLL VCO输入分频为1,8/1 = 8MHz
RCC_OscInitStruct.PLL.PLLN = 20; // 配置PLL VCO输入倍增为20,8MHz*20 = 160MHz
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // SAI时钟7分频,160/7 = 22.857143MHz
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // SDMMC、RNG、USB时钟2分频,160/2 = 80MHz
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // 系统主时钟分区2分频,160/2 = 80MHz
// RCC时钟配置,出错则进入错误处理函数
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
// 初始化CPU,AHB和APB总线时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; // 需要配置的时钟HCLK、SYSCLK、PCLK1、PCLK2
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 配置系统时钟为PLLCLK输入,80MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟为系统时钟1分频,80/1 = 80MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1时钟为系统时钟1分频,80/1 = 80MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2时钟为系统时钟1分频,80/1 = 80MHz
// RCC时钟配置,出错则进入错误处理函数
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) // HCLK=80MHz,Vcore=3.3V,所以选择SW4(FLASH_LATENCY_4)
{
_Error_Handler(__FILE__, __LINE__);
}
// 初始化外设时钟
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2
|RCC_PERIPHCLK_LPUART1|RCC_PERIPHCLK_LPTIM1
|RCC_PERIPHCLK_I2C2|RCC_PERIPHCLK_ADC; // 需要初始化的外设时钟:USART1、USART2、LPUART1、LPTIM1、I2C2、ADC
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; // 配置串口USART1时钟为PCLK2,80MHz
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; // 配置串口USART2时钟为PCLK1,80MHz
PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_HSI; // 配置LPUART时钟为HSI,16MHz
PeriphClkInit.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1; // 配置I2C2时钟为PCLK1,80MHz
PeriphClkInit.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE; // 配置LPTIM1时钟为LSE,32.768KHz
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; // 配置ADC时钟为PLLSAI1,现在为80MHz,下面会重新定义
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE; // 配置PLLSAI1时钟为HSE,8MHz
PeriphClkInit.PLLSAI1.PLLSAI1M = 1; // 配置PLLSAI1分频为1
PeriphClkInit.PLLSAI1.PLLSAI1N = 8; // 配置PLLSAI1倍增为8
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; // SAI时钟7分频,64/7 = 9.142857MHz
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2; // SDMMC、RNG、USB时钟2分频,64/2 = 32MHz
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; // 系统主时钟分区2分频,64/2 = 32MHz
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK; // 配置PLLSAI1输出为ADC1时钟,也就是配置ADC1时钟,32MHz
// 外设时钟配置,出错则进入错误处理函数
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
// 配置内部主稳压器输出电压,配置为稳压器输出电压范围1模式,也就是:典型输出电压为1.2V,系统频率高达80MHz
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
 
// 配置系统定时器中断时间,配置为HCLK的千分频
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
// 配置系统定时器,配置为HCLK
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
// 系统定时器中断配置,设置系统定时器中断优先级最高(为0),且子优先级最高(为0)
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
 
 
//******************************************************************
// fn : _Error_Handler
//
// brief : 错误处理程序
//
// param : none
//
// return : none
void _Error_Handler(char * file, int line)
{
// 暂时未处理任何事情,用户可用来添加自己的功能来报告HAL错误返回状态
while(1)
{
}
}
 
</syntaxhighlight>
 
==== main.c ====
main.c文件中,我们只放置了3个函数,以后的所有例程也只有这3个函数,下面我们将简要说明各个函数的功能。
硬件初始化函数,顾名思义,就是我们初始化硬件驱动的函数,在这个实验中,我们初始化了LCD的驱动文件。<syntaxhighlight lang="c++" line="1" start="27">void HardWare_Init(void){ // 初始化LCD BSP_EvbLcdInit();}</syntaxhighlight>LiteOS任务初始化函数,我们会在这个函数中初始化我们用户新建的task任务,在这个TFT实验中,我们没有独立的任务,仅仅初始化了GUI图形化界面。<syntaxhighlight lang="c++" line="1" start= "41">void LosTask_Init(void){ // 初始化图形接口 GUI_Init(); GUI_DispString("LiteOS"); GUI_DispNextLine(); GUI_DispString("01_los_lcd");}</syntaxhighlight>main.()函数中,我们首先初始化HAL和系统时钟,接着我们初始化了LiteOS内核,使能LiteOS系统tick中断,然后我们分别初始化了我们所使用的硬件驱动和los任务,最后我们开始<syntaxhighlight lang="c ++" line="1" start="58">int main(void){ UINT32 uwRet; // 初始化硬件 HAL_Init(); SystemClock_Config(); // 初始化LOS内核 uwRet = LOS_KernelInit(); if (uwRet !=LOS_OK) { return LOS_NOK; } // 使能LOS系统tick中断 uwRet =LOS_EnableTick(); if (uwRet !=LOS_OK) { return LOS_NOK; } // 初始化开发板硬件 HardWare_Init(); // 初始化用户任务 LosTask_Init(); // 运行LOS (void)LOS_Start(); for(;;);}</syntaxhighlight>
=== los_bsp_lcd.c ===
510
个编辑