赞
踩
通过定时器1实现间隔100ms的双向流水灯
1、使用PC8~PC15控制LED灯亮灭,LD1 - LD8为引脚的别名
2、使用PD2控制锁存器,LEDLOCK为PD2的别名
3、HSE选用石英/陶瓷谐振器
4、GPIO均设置为输出模式,使用默认的GPIO配置
5、时钟配置为80MHz
6、配置定时器TIM1,时钟源选择内部时钟
7、配置定时时间
Prescaler=1000-1
Counter Period=80-1
定时器时钟频率为80MHZ,即80 000 000HZ
定时时间 = (Prescaler+1 ) X (Counter Period+1) X 1/ 定时器时钟频率(信号的周期)
定时时间 =1000 X 80 / 80000000=0.001s=1ms
知识补充:
a. APB2负责AD,I/O,高级TIM,串口1。
APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM
TIM1是高级定时器,包括了基本定时器和通用定时器的所有功能。
b. HZ是赫兹,频率单位,1MHZ(兆赫)=1000KHZ(千赫)=1000000HZ
c. 定时器发生中断时间的计算方法:
定时时间 = (Prescaler+1 ) X (Counter Period+1) X 1/ 定时器时钟频率(信号的周期)
时钟信号1KHz,Prescaler为9,Counter Period为999,定时时间?
定时时间=10x1000x1/1000=10s=10000ms=10s
Keil配置参考ADC篇,不赘述了
Keil配置
main.c中添加头文件。(注:所有代码放到BEGIN和END之间,防止重新生成代码时将原来的代码覆盖掉)
#include "lcd.h"
//实现间隔为100ms的流水灯 /// void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //周期运行回调,配置定时进入中断 { static uint16_t led = 0x0001, i = 0, flag = 0 ,counter = 0; if(++counter == 100){ //100*1ms=100ms counter = 0; GPIOC->ODR = ~(led << (8 + i)); //通过位运算设置输出端口寄存器ODR的值,从而控制LED的亮灭 HAL_GPIO_WritePin(LEDLOCK_GPIO_Port, LEDLOCK_Pin, GPIO_PIN_SET); //打开锁存器 GPIOD->BSRR |= GPIO_PIN_2; __nop();__nop();__nop(); //一个__nop()函数延时一个机器周期的时间 HAL_GPIO_WritePin(LEDLOCK_GPIO_Port, LEDLOCK_Pin, GPIO_PIN_RESET); //关闭锁存器 GPIOD->BRR |= GPIO_PIN_2; if(flag == 0) //flag作为流水灯方向的标志位 当flag = 0时,LD1流向LD8 ; 当flag = 1时,LD8流向LD1 { ++i; if(i == 7){ flag = 1; } } else { --i; if(i == 0){ flag = 0; } } } HAL_TIM_Base_Start_IT(&htim1); //使能定时器1中断 }
HAL_GPIO_WritePin(GPIOC,LD1_Pin|LD2_Pin | LD3_Pin|LD4_Pin | LD5_Pin|LD6_Pin |LD7_Pin|LD8_Pin, GPIO_PIN_SET); //LED全灭 等价于GPIOC->ODR = 0xFFFF;
HAL_GPIO_WritePin(LEDLOCK_GPIO_Port, LEDLOCK_Pin, GPIO_PIN_SET); //打开锁存器 等价于GPIOD->BSRR |= GPIO_PIN_2;
__nop();__nop();__nop(); //一个__nop()函数延时一个机器周期的时间 表示空循环一个机器指令的时间,STM32中1/80M=0.0125ns ; C51中12M中表示1us;6M中表示2us;24M中表示0.5us STM32中1/80M=0.0125ns
HAL_GPIO_WritePin(LEDLOCK_GPIO_Port, LEDLOCK_Pin, GPIO_PIN_RESET); //关闭锁存器 等价于GPIOD->BRR |= GPIO_PIN_2;
HAL_TIM_Base_Start_IT(&htim1); //使能定时器1中断
LCD_Init(); LCD_Clear(Blue); LCD_SetBackColor(Blue); LCD_SetTextColor(White); LCD_DisplayStringLine(Line0, (uint8_t *)" "); LCD_DisplayStringLine(Line1, (uint8_t *)" "); LCD_DisplayStringLine(Line2, (uint8_t *)" TIM Test "); LCD_DisplayStringLine(Line3, (uint8_t *)" "); LCD_DisplayStringLine(Line4, (uint8_t *)" "); LCD_SetBackColor(White); LCD_SetTextColor(Blue); LCD_DisplayStringLine(Line5, (uint8_t *)" "); LCD_DisplayStringLine(Line6, (uint8_t *)" TIM1:100ms "); LCD_DisplayStringLine(Line7, (uint8_t *)" "); LCD_DisplayStringLine(Line8, (uint8_t *)" "); LCD_DisplayStringLine(Line9, (uint8_t *)" ");
可以看到配置效果
/* TIM1 init function */ void MX_TIM1_Init(void) //(999+1)*(79+1)/80 000 000=1000*80/80 000 000 =0.001s=1ms { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; htim1.Instance = TIM1; htim1.Init.Prescaler = 1000-1; //设置为1000-1 htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 79; //设置为80-1 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) { Error_Handler(); } }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void LCD_Init(void);
void LCD_SetTextColor(vu16 Color);
void LCD_SetBackColor(vu16 Color);
void LCD_Clear(u16 Color);
void LCD_DisplayStringLine(u8 Line, u8 *ptr);
可以看到双向流水灯现象,即LD1流向LD8,LD8流向LD1,如此循环下去
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。