之前使用Arduino
和M3
内核的MCU时,发现有一种非阻塞程序流程,例如Arduino
的mills()
函数,STM32
的HAL_GetTick()
都可以获取芯片启动到现在的时间,这样我们就能在一个while(1)
里面完成各个传感器的数据获取,举例如下:
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
//类似于Arduino中ESP8266时间mills()的写法?
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);
}
/* 1ms 按键扫描 */
if (HAL_GetTick() - tick1 >= 1) {
tick1 = HAL_GetTick();
key_check_all_loop_1ms();
}
/* Key按键按下查询 */
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();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
本次我们去查看CH32V307的手册,看到对SysTick
有如下描述:
查看系统时钟树结构,我们发现SysTick
的时钟源来自于HCLK
,使用中大多/8
分频,即SysTick=HCLK/8
,后面我们会在代码中看到。
我们打开工程项目下的debug.c
,里面包含了Delay
函数的初始化及实现。
SysTick
的时钟分频设置在system_ch32v30x.c
中的SetSysClockToXX()
函数中,其中XX
为当前系统时钟SYSCLK_FREQ
,通过#define
进行设置。
Delay_Init
:/*********************************************************************
* @fn Delay_Init
*
* [url=home.php?mod=space&uid=2666770]@Brief[/url] Initializes Delay Funcation.
*
* [url=home.php?mod=space&uid=1141835]@Return[/url] none
*/
void Delay_Init(void)
{
p_us = SystemCoreClock / 8000000;// 72m/8000000=9
p_ms = (uint16_t)p_us * 1000;// 9*1000 = 9000
}
其中SystemCoreClock / 8000000;
中的8_000_000为上文中提到的8分频,乘以s->us的1_000_000单位转换,这样就可以得到每个us,SysTick的计数次数。同理,ms的计算一样,用us的乘以1000即可。
Delay_Ms
的实现:/*********************************************************************
* @fn Delay_Ms
*
* @brief Millisecond Delay Time.
*
* [url=home.php?mod=space&uid=3142012]@param[/url] n - Millisecond number.
*
* @return None
*/
void Delay_Ms(uint32_t n)
{
uint32_t i;
// 清除比较计数器结果
SysTick->SR &= ~(1 << 0);
// 得到需要计数的时钟数目
i = (uint32_t)n * p_ms;
// 设置比较计数器计数次数
SysTick->CMP = i;
// 向下计数,设置输出比较值,启动系统计数器 STK
SysTick->CTLR |= (1 << 4) | (1 << 5) | (1 << 0);
// 等待比较计数器比较结果为1
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
// 停止系统计数器 STK
SysTick->CTLR &= ~(1 << 0);
}
可以看到共使用了SR/CMP/CTLR
三个寄存器,我们查询【手册】,查看寄存器定义:
STK_CTLR
寄存器SR
寄存器CMP
寄存器分为CMPLR
和CMPHR
debug.c
:/********************************** (C) COPYRIGHT *******************************
* File Name : debug.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : This file contains all the functions prototypes for UART
* Printf , Delay functions.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#include "debug.h"
static uint8_t p_us = 0;
static uint16_t p_ms = 0;
/*********************************************************************
* @fn Delay_Init
*
* @brief Initializes Delay Funcation.
*
* @return none
*/
void Delay_Init(void)
{
p_us = SystemCoreClock / 8000000;// 72m/8000000=9
p_ms = (uint16_t)p_us * 1000;// 9*1000 = 9000
}
/*********************************************************************
* @fn Delay_Us
*
* @brief Microsecond Delay Time.
*
* @param n - Microsecond number.
*
* @return None
*/
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);
}
/*********************************************************************
* @fn Delay_Ms
*
* @brief Millisecond Delay Time.
*
* @param n - Millisecond number.
*
* @return None
*/
void Delay_Ms(uint32_t n)
{
uint32_t i;
// 清除比较计数器结果
SysTick->SR &= ~(1 << 0);
// 得到需要计数的时钟数目
i = (uint32_t)n * p_ms;
// 设置比较计数器计数次数
SysTick->CMP = i;
// 向下计数,设置输出比较值,启动系统计数器 STK
SysTick->CTLR |= (1 << 4) | (1 << 5) | (1 << 0);
// 等待比较计数器比较结果为1
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
// 停止系统计数器 STK
SysTick->CTLR &= ~(1 << 0);
}
更多回帖