0. 前言
之前使用Arduino
和M3
内核的MCU时,发现有一种非阻塞程序流程,例如Arduino
的mills()
函数,STM32
的HAL_GetTick()
都可以获取芯片启动到现在的时间,这样我们就能在一个while(1)
里面完成各个传感器的数据获取,举例如下:
while (1) {
if ((HAL_GetTick() - tick >= 100)) {
tick = HAL_GetTick();
u8g2_ClearBuffer(&u8g2);
sprintf((char*)Message, "Encoder");
u8g2_DrawUTF8(&u8g2, 40, 16 - 2, (char*)Message);
sprintf((char*)Message, "%d", enc_key_value_buff);
u8g2_DrawStr(&u8g2, 110, 16 - 2, (char*)Message);
MessageLength = sprintf((char*)Message, "Counter: %d
", (int)htim1.Instance->CNT);
HAL_UART_Transmit(&huart2, Message, MessageLength, 100);
u8g2_DrawStr(&u8g2, 15, 32 - 4, (char*)Message);
UpdateAudioVolume();
MessageLength = sprintf((char*)Message, "Volume: %d
", AudioVolume);
HAL_UART_Transmit(&huart2, Message, MessageLength, 100);
u8g2_DrawStr(&u8g2, 15, 48 - 6, (char*)Message);
u8g2_DrawRBox(&u8g2, 14, 50, AudioVolume, 12, 4);
u8g2_SendBuffer(&u8g2);
}
if (HAL_GetTick() - tick1 >= 1) {
tick1 = HAL_GetTick();
key_check_all_loop_1ms();
}
if (HAL_GetTick() - tick2 >= 10) {
tick2 = HAL_GetTick();
enc_key_value = key_read_value();
if (enc_key_value == KEY0_UP_SHORT) {
enc_key_value_buff = 1;
} else if (enc_key_value == KEY0_UP_DOUBLE) {
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
enc_key_value_buff = 2;
} else if (enc_key_value == KEY0_LONG) {
enc_key_value_buff = 3;
}
}
if (HAL_GetTick() - tick3 >= 50) {
tick3 = HAL_GetTick();
}
}
1. SysTick
CH32V307手册下载地址
本次我们去查看CH32V307的手册,看到对SysTick
有如下描述:
查看系统时钟树结构,我们发现SysTick
的时钟源来自于HCLK
,使用中大多/8
分频,即SysTick=HCLK/8
,后面我们会在代码中看到。
2. 源码分析
我们打开工程项目下的debug.c
,里面包含了Delay
函数的初始化及实现。
SysTick
的时钟分频设置在system_ch32v30x.c
中的SetSysClockToXX()
函数中,其中XX
为当前系统时钟SYSCLK_FREQ
,通过#define
进行设置。
void Delay_Init(void)
{
p_us = SystemCoreClock / 8000000;
p_ms = (uint16_t)p_us * 1000;
}
其中SystemCoreClock / 8000000;
中的8_000_000为上文中提到的8分频,乘以s->us的1_000_000单位转换,这样就可以得到每个us,SysTick的计数次数。同理,ms的计算一样,用us的乘以1000即可。
void Delay_Ms(uint32_t n)
{
uint32_t i;
SysTick->SR &= ~(1 << 0);
i = (uint32_t)n * p_ms;
SysTick->CMP = i;
SysTick->CTLR |= (1 << 4) | (1 << 5) | (1 << 0);
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
SysTick->CTLR &= ~(1 << 0);
}
可以看到共使用了SR/CMP/CTLR
三个寄存器,我们查询【手册】,查看寄存器定义:
STK_CTLR
寄存器
SR
寄存器
CMP
寄存器分为CMPLR
和CMPHR
4. 最后,附上debug.c的代码:
#include "debug.h"
static uint8_t p_us = 0;
static uint16_t p_ms = 0;
void Delay_Init(void)
{
p_us = SystemCoreClock / 8000000;
p_ms = (uint16_t)p_us * 1000;
}
void Delay_Us(uint32_t n)
{
uint32_t i;
SysTick->SR &= ~(1 << 0);
i = (uint32_t)n * p_us;
SysTick->CMP = i;
SysTick->CTLR |= (1 << 4) | (1 << 5) | (1 << 0);
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
SysTick->CTLR &= ~(1 << 0);
}
void Delay_Ms(uint32_t n)
{
uint32_t i;
SysTick->SR &= ~(1 << 0);
i = (uint32_t)n * p_ms;
SysTick->CMP = i;
SysTick->CTLR |= (1 << 4) | (1 << 5) | (1 << 0);
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
SysTick->CTLR &= ~(1 << 0);
}