嵌入式技术
嵌入式计时器是一种在嵌入式系统中用于计时、计数和测量时间间隔的设备。它们通常用于生成精确的延迟、测量输入信号的频率或产生PWM信号。嵌入式计时器主要包括硬件计时器(例如定时器/计数器、实时时钟)和软件计时器。
使用STM32F10x微控制器实现延时功能的示例代码( 硬件实现 )。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
// 配置TIM2以生成时间基准
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能TIM2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置TIM2基本参数
TIM_TimeBaseStructure.TIM_Period = 999; // 设置计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 设置预分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 使能TIM2
TIM_Cmd(TIM2, ENABLE);
}
void delay_ms(uint16_t ms)
{
uint16_t i;
for (i = 0; i < ms; i++)
{
TIM_SetCounter(TIM2, 0);
while (TIM_GetCounter(TIM2) < 1000)
{
}
}
}
int main(void)
{
// 初始化系统配置
SystemInit();
// 配置TIM2以生成时间基准
TIM2_Configuration();
while (1)
{
// 延时1000毫秒
delay_ms(1000);
// ...其他代码(可以根据需要执行一些动作)...
}
}
使用STM32F10x微控制器实现延时功能的示例代码( 软件实现 )。。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
// 获取系统时钟
uint32_t SystemCoreClock;
// 延时微秒
void delay_us(uint32_t us)
{
uint32_t i, j;
uint32_t count = (SystemCoreClock / 8000000) * us;
for (i = 0; i < count; i++)
{
for (j = 0; j < 2; j++)
{
__NOP(); // No Operation指令,用于延时
}
}
}
// 延时毫秒
void delay_ms(uint32_t ms)
{
uint32_t i;
for (i = 0; i < ms; i++)
{
delay_us(1000);
}
}
int main(void)
{
// 初始化系统配置
SystemInit();
// 获取系统时钟
SystemCoreClock = SystemCoreClock;
while (1)
{
// 延时1000毫秒
delay_ms(1000);
// ...其他代码(可以根据需要执行一些动作)...
}
}
使用STM32F10x微控制器的计数器功能的示例代码( 硬件实现 )。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
void TIM2_Counter_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
// 使能TIM2和GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIOA0作为输入,上拉
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置TIM2基本参数
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 配置TIM2的输入捕获
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM2, &TIM_ICInitStructure);
// 使能TIM2
TIM_Cmd(TIM2, ENABLE);
}
int main(void)
{
uint16_t counter_value;
TIM2_Counter_Config(); // 配置TIM2计数器
while (1)
{
counter_value = TIM_GetCounter(TIM2); // 读取TIM2计数器的值
// ...其他代码(可以根据需要处理计数值)...
}
}
使用STM32F10x微控制器的计数器功能的示例代码( 软件实现 )。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_exti.h"
#include "misc.h"
volatile uint32_t pulseCounter = 0;
void EXTI0_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIOA0作为输入,上拉
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 使能AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 配置GPIOA0为外部中断源
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
// 配置EXTI线0
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 配置NVIC
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET)
{
pulseCounter++; // 增加脉冲计数值
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
}
}
int main(void)
{
uint32_t counter_value;
EXTI0_Configuration(); // 配置外部中断(EXTI)
while (1)
{
counter_value = pulseCounter; // 读取脉冲计数值
// ...其他代码(可以根据需要处理计数值)...
}
}
使用STM32F10x微控制器生成PWM信号的示例代码( 硬件实现 )。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
// 配置TIM3以生成PWM信号
void TIM3_PWM_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 使能TIM3和GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIOB5为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置TIM3基本参数
TIM_TimeBaseStructure.TIM_Period = 19999; // 设置计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 设置预分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 配置TIM3通道2的PWM输出
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 10000; // 初始占空比设置为50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
// 使能TIM3
TIM_Cmd(TIM3, ENABLE);
}
int main(void)
{
// 配置TIM3以生成PWM信号
TIM3_PWM_Configuration();
while (1)
{
// ...其他代码(可以根据需要调整PWM信号的占空比等)...
}
}
使用STM32F10x微控制器生成PWM信号的示例代码( 软件实现 )。
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
// 配置TIM2以生成时间基准
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能TIM2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置TIM2基本参数
TIM_TimeBaseStructure.TIM_Period = 999; // 设置计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 设置预分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 使能TIM2
TIM_Cmd(TIM2, ENABLE);
}
void delay_us(uint16_t us)
{
uint16_t i;
for (i = 0; i < us; i++)
{
TIM_SetCounter(TIM2, 0);
while (TIM_GetCounter(TIM2) < 1)
{
}
}
}
// 配置GPIOB5输出
void GPIOB5_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIOB5为推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void Software_PWM(uint16_t onTime, uint16_t offTime)
{
GPIO_SetBits(GPIOB, GPIO_Pin_5);
delay_us(onTime);
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
delay_us(offTime);
}
int main(void)
{
uint16_t onTime = 5000; // 设定PWM信号的占空比时间 (单位:微秒)
uint16_t offTime = 5000; // 设定PWM信号的空闲时间 (单位:微秒)
// 配置TIM2以生成时间基准
TIM2_Configuration();
// 配置GPIOB5输出
GPIOB5_Configuration();
while (1)
{
// 使用软件PWM模拟信号输出
Software_PWM(onTime, offTime);
// ...其他代码(可以根据需要调整PWM信号的占空比等)...
}
}
硬件实现和软件实现在嵌入式系统中通常涉及到相同的功能,但它们的实现方式和性能有所不同。以下是硬件实现与软件实现的主要区别:
说了这么多,其实定时器的本质是一种特殊的计数器,它能够按照预定的频率自动递增(或递减)计数值。定时器在达到预设的计数值时会触发事件,例如产生中断、翻转输出引脚状态等。定时器是微控制器内部的一个硬件模块,可以独立于CPU运行,实现精确的时间间隔和事件触发。
定时器的工作原理如下:
定时器在嵌入式系统中有许多应用,如实现精确延时、周期性任务调度、PWM信号生成、脉冲宽度测量等。定时器提供了一种高精度、低资源占用的时间控制手段,可以有效地支持复杂的嵌入式应用。
既然定时器的本质是一个累加逻辑,那接下来我们尝试在simulink中用多种方法实现定时器功能,例如当某个功能触发时开始计时,功能停止时计时保持不变,当计时累计达到某个设定值时触发另一个事件执行。(夏季空调内循环制冷,计时20min后开启30s外循环换气)
Matlab Function的实现方式
MATLAB Function 模块可以帮助我们在Simulink 模型中实现MATLAB函数的功能,也可以生成可读、高效、紧凑的 C代码,应用于嵌入式系统中。
图中u2模拟计时器的条件,我们设定为周期为5,占空比为50%的方波信号,t2等于Simulnk模型的仿真步长,x是上一时刻的计时数值。MATLAB Function中的代码如下:
function y = fcn(u,t,x)
if u == 1
x = x + t;
end
y = x;
配置参数
运行结果
Simulink基础模块的实现方式
使用基础模块搭建的Simulink模型如下图,主要借助switch和add来实现。
S****tateflow状态机的实现方式
计时器功能也可以分为两个状态,即累加状态和保持状态,所以也可以使用Stateflow来实现。
chart内部如下
Stateflow流程图的实现方式
在Simulink软件开发过程中,对于比较简单的Stateflow逻辑,尤其是条件选择逻辑,可以使用流程图代替状态图,以简化逻辑。
chart内部如下
simulink中还有一些和计数相关的模块如下
自由计数器(Counter Free-Running)是一种无限制的计数器,可以无限地递增或递减。它通常用于计算脉冲信号的数量、测量时间等。在 Simulink 中,您可以使用Discrete库中的Counter Free-Running模块来创建自由计数器。
Conter模块可以通过指定的数据范围实现向上计数或向下计数。当选择Count direction参数为向上计数时,模块将使能 Inc (增量)端口;当选择Count direction参数为向下计数时,模块将使能 Dec (减量)端口。如果Count event参数为Free running,模块将禁用Inc或Dec端口,并且使用固定时间间隔进行计数。针对于Count event参数的所有其他设定,每当在Inc或Dec输入端口发生触发事件时,模块都会使计数器递增或递减。当触发事件发生在Rst端口时,模块复位,计数器恢复到初始设定状态。
限制计数器(Counter Limited)是一种具有上限或下限的计数器。当计数器达到预设的限制值时,它会回到初始值重新开始计数。您可以使用Simulink > Discrete库中的Counter Limited模块来创建限制计数器。
让我们重新回到最开始的例子:夏季空调内循环制冷,计时20min后开启30s外循环换气,这个例子包含两个计时器和两次事件触发和状态切换,我们试着用simulink的基础模块实现此功能。
C代码如下:
#include < stdint.h >
#include < stdbool.h >
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
// Define constants for internal and external circulation times in milliseconds
#define INTERNAL_CIRCULATION_TIME (20 * 60 * 1000) // 20 minutes
#define EXTERNAL_CIRCULATION_TIME (30 * 1000) // 30 seconds
// Function prototypes for internal and external circulation control
void set_internal_circulation();
void set_external_circulation();
// Function prototype for millisecond delay
void delay_ms(uint32_t ms);
int main(void)
{
uint32_t internal_timer = 0; // Timer to track the time spent in internal circulation mode
uint32_t external_timer = 0; // Timer to track the time spent in external circulation mode
bool is_internal_circulation = true; // Flag to indicate whether the current mode is internal circulation
// Set the initial mode to internal circulation
set_internal_circulation();
// Main loop
while (1)
{
delay_ms(1); // 1 millisecond delay
// If the current mode is internal circulation
if (is_internal_circulation)
{
internal_timer += 1; // Increment the internal timer
// If the internal timer reaches the predefined internal circulation time
if (internal_timer >= INTERNAL_CIRCULATION_TIME)
{
// Switch to external circulation mode
set_external_circulation();
is_internal_circulation = false;
// Reset the internal timer
internal_timer = 0;
}
}
else // If the current mode is external circulation
{
external_timer += 1; // Increment the external timer
// If the external timer reaches the predefined external circulation time
if (external_timer >= EXTERNAL_CIRCULATION_TIME)
{
// Switch to internal circulation mode
set_internal_circulation();
is_internal_circulation = true;
// Reset the external timer
external_timer = 0;
}
}
}
return 0;
}
// Function to set internal circulation mode
void set_internal_circulation()
{
// Implement your logic to set internal circulation here
}
// Function to set external circulation mode
void set_external_circulation()
{
// Implement your logic to set external circulation here
}
// Function to provide a millisecond delay
void delay_ms(uint32_t ms)
{
// Implement a software delay function here, or use the provided hardware timer delay function
}
simulink模型如下:
全部0条评论
快来发表一下你的评论吧 !