瑞萨RA4M2的AGT是一个专为低功耗和灵活定时设计的16位定时器外设。与侧重高性能PWM输出的GPT不同,AGT的核心优势在于其低功耗特性——即使在待机模式下也能工作,非常适合电池供电或需要低功耗运行的应用
一:RA4M2 定时器知识:
RA4M2芯片拥有6个16位的AGT通道(AGT0-AGT5),它是一个递减计数器,支持多种工作模式:
定时器模式:最基本的定时功能,计数到0时产生下溢中断。
脉冲输出模式:每次计数器下溢时,在AGTOn引脚上自动翻转电平,无需CPU干预即可产生方波。
事件计数器模式:通过AGTIO引脚输入外部事件,对事件个数进行计数。
脉冲宽度/周期测量模式:测量外部输入信号的高/低电平宽度或周期,常用于传感器信号解析
PWM(脉冲宽度调制)模式:利用比较匹配功能,在AGTOA/B引脚上输出占空比可调的PWM波,可用于LED调光等
二:FSP配置如下所示:

General:
Mode:选择 periodic(周期模式)。
Period :1
Count Source LOCO
Interrupts:
Callback:g_timer0_callback
Underflow Interrupt Priority:Priority15
三:软件编写:
3.1 定时器的初始化
void R_AGT_Time0ing_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_AGT_Open(&g_timer0_ctrl, &g_timer0_cfg);
/* Handle any errors. This function should be defined by the user.*/
assert(FSP_SUCCESS == err);
/* Start the timer.*/
(void) R_AGT_Start(&g_timer0_ctrl);
}在AGT初始化函数里面,首先调用R_AGT_Open函数初始化AGT模块,随后调用R_AGT_Start函数来启动AGT定时器。
3.2 定时器的回调函数:
int flag = 0 ;int iLEDCount = 0 ;
void g_timer0_callback(timer_callback_args_t *p_args)
{ if (TIMER_EVENT_CYCLE_END == p_args->event)
{#if LEDMode
count0Point++ ; if(count0Point>=1000)
{
count0Point = 0 ;
iLEDCount++ ; if(iLEDCount%2 ==0)
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_02, BSP_IO_LEVEL_LOW);
} else
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_02, BSP_IO_LEVEL_HIGH);
}
}#endif#if TaskMode
Task_Marks_Handler_Callback();#endif
}
}中断回调函数非常简单,使用if语句判断引起中断的事件,若是定时器溢出中断(TIMER_EVENT_CYCLE_END)则1ms时间间隔加1,加到1000ms时对中断时间到了1S。下载之后,可以看到板载的LED灯以1s 的时间间隔闪烁。四:添加时间调度
4.1 任务调度的基本概念
在C语言里,任务调度指的是对多个任务(也被叫做线程或者进程)的执行顺序进行管理,以此来达成高效利用系统资源的目的。下面为你详细介绍任务调度的相关概念和实现方法。
4.2:任务调度的概念思想:
抢占式调度:在这种调度方式下,操作系统能够依据任务优先级,强行暂停当前正在执行的任务,转而执行其他任务。
非抢占式调度:采用这种调度方式时,任务只有在主动放弃 CPU 控制权的情况下,其他任务才有机会执行。
实时调度:实时调度的核心是保证任务能在严格的时间限制内完成,它又可以细分为硬实时调度和软实时调度。
优先级调度:优先级调度会为每个任务分配一个优先级,系统会优先执行优先级较高的任务。
4.3:任务调度的关键要点
上下文切换:在任务切换时,需要保存当前任务的状态(例如寄存器值),并恢复下一个任务的状态。
临界区保护:对于共享资源,要使用互斥锁、信号量等机制来避免竞态条件。
任务同步:可以通过信号量、事件标志组等方式实现任务间的同步。
堆栈管理:每个任务都有自己独立的堆栈,必须确保堆栈大小足够,防止溢出。
常用的任务调用有Free Rtos,OS,RT-threard等等实时操作系统专为嵌入式系统设计,提供了强大的任务调度功能,
这里和大家分享一个简单任务调度器。创建任务队列。然后按照一定时间间隔来处理任务。
4.4 底层驱动代码如下,可以移植到其他架构的平台
/========================================================================
// 函数: TASK_COMPONENTS
// 描述: 添加任务列表
// 参数: None.
// 返回: None.
// 版本: V1.0, 2026-04-22
//========================================================================static TASK_COMPONENTS Task_Comps[]=
{
{0, 1000,1000, task_1000ms}, //task 1 Period: 1000ms
{0, 100,100, task_100ms}, //task 2 Period: 500ms
{0, 1,1, task_1ms}, //task 2 Period: 500ms
};char Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);
//========================================================================
// 函数: Task_Handler_Callback
// 描述: 任务标记回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2026-04-22
//========================================================================void Task_Marks_Handler_Callback(void)
{ char i; for(i=0; i<Tasks_Max; i++)
{ if(Task_Comps[i].TIMCount) /* If the time is not 0 */
{ Task_Comps[i].TIMCount--; /* Time counter decrement */
if(Task_Comps[i].TIMCount == 0) /* If time arrives */
{
/*Resume the timer value and try again */ Task_Comps[i].TIMCount = Task_Comps[i].TRITime;
Task_Comps[i].Run = 1; /* The task can be run */
}
}
}
}
//========================================================================
// 函数: Task_Pro_Handler_Callback
// 描述: 任务处理回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2026-04-22
//========================================================================void Task_Pro_Handler_Callback(void)
{ char i; for(i=0; i<Tasks_Max; i++)
{ if(Task_Comps[i].Run) /* If task can be run */
{ Task_Comps[i].Run = 0; /* Flag clear 0 */
Task_Comps[i].TaskHook(); /* Run task */
}
}
}4.5 两个不同的任务
void task_100ms(void)
{
flag100data++ ; if(flag100data%2 ==0)
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
} else
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
}
}烧录之后,可以看到LED可以正常闪烁,这样任务调度就移植好了,下面在此基础上可以对其他的外设进行调节。
我要赚赏金
