AI8051U学习打卡(六)
6. 定时器任务调度
6.1. 任务1:
用一个定时器实现这个任务。LED1实现0.3秒取反一次,LED2实现0.6
秒取反一次,LED3实现0.9秒取反一次。
#include "../COMM/AI8051U.h"
#include "../COMM/usb.h"
#include "stdio.h"
#include "intrins.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
//==========================================================================
void Delay20ms(void) //@40MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 199998UL;
while (i) i--;
}
uint16_t Timer0_cnt[3] ={0,0,0};//定时器0任务周期时间数组
uint8_t i;
void Timer0_Init(void) //1毫秒@40MHz
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xFB; //设置定时初始值
TH0 = 0xF2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
uint8_t led1_state = 0;
uint8_t led2_state = 0;
uint8_t led3_state = 0;
uint8_t run_state = 0;
/******************** 主函数 **************************/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0xff; //设置为推挽输出
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
P00 = 0; //LED Power On
usb_init(); //USB CDC 接口配置
IE2 |= 0X80; //开启USB中断
Timer0_Init(); //定时器0初始化
EA = 1; //开启总中断
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while (1)
{
if (bUsbOutReady)
{
// USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
printf("hello mikeybie\r\n");
usb_OUT_done();
}
//任务1
if(Timer0_cnt[0] >= 300)
{
Timer0_cnt[0] = 0;
led1_state ^= 1;
P00 = led1_state;
}
if(Timer0_cnt[1] >= 600)
{
Timer0_cnt[1] = 0;
led2_state ^= 1;
P01 = led2_state;
}
if(Timer0_cnt[2] >= 900)
{
Timer0_cnt[2] = 0;
led3_state ^= 1;
P02 = led3_state;
}
}
}
void Timer0_Isr(void) interrupt 1
{
for(i=0;i<3;i++)
{
Timer0_cnt[i]++;
}
}

6.2. 任务2:
数组点亮LED,实现流水灯。
#include "../COMM/AI8051U.h"
#include "../COMM/usb.h"
#include "stdio.h"
#include "intrins.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
//==========================================================================
void Delay20ms(void) //@40MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 199998UL;
while (i) i--;
}
/*
b0 b1 b7
低 高
LED0 —— LED7
0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 1 0 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 1 1 0 1 1 1
1 1 1 1 1 0 1 1
1 1 1 1 1 1 0 1
1 1 1 1 1 1 1 0
*/
uint8_t LED_State[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//P0 LED控制数组
uint8_t LED_pos = 0;//LED控制数组索引
uint16_t Timer0_cnt[3] ={0,0,0};//定时器0任务周期时间数组
uint8_t i;
void Timer0_Init(void) //1毫秒@40MHz
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xFB; //设置定时初始值
TH0 = 0xF2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
/******************** 主函数 **************************/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0xff; //设置为推挽输出
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
P00 = 0; //LED Power On
usb_init(); //USB CDC 接口配置
IE2 |= 0X80; //开启USB中断
Timer0_Init(); //定时器0初始化
EA = 1; //开启总中断
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while (1)
{
if (bUsbOutReady)
{
// USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
printf("hello mikeybie\r\n");
usb_OUT_done();
}
//任务2
if(Timer0_cnt[0] >= 500)
{
Timer0_cnt[0] = 0;
P0 = ~LED_State[LED_pos];
if(++LED_pos >= 8) LED_pos = 0;
}
}
}
void Timer0_Isr(void) interrupt 1
{
for(i=0;i<3;i++)
{
Timer0_cnt[i]++;
}
}

6.3. 任务3:
按键按下一次,LED通过数组移动一下。搭配定时器扫描消抖,不阻塞串口发送,串口稳定1s发一次。
#include "../COMM/AI8051U.h"
#include "../COMM/usb.h"
#include "stdio.h"
#include "intrins.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
//==========================================================================
void Delay20ms(void) //@40MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 199998UL;
while (i) i--;
}
/*
b0 b1 b7
低 高
LED0 —— LED7
0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 1 0 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 1 1 0 1 1 1
1 1 1 1 1 0 1 1
1 1 1 1 1 1 0 1
1 1 1 1 1 1 1 0
*/
uint8_t LED_State[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//P0 LED控制数组
uint8_t LED_pos = 0;//LED控制数组索引
uint16_t Timer0_cnt[3] ={0,0,0};//定时器0任务周期时间数组
uint8_t i;
uint8_t KEY_press = 0;//按键扫描消抖变量
void Timer0_Init(void) //1毫秒@40MHz
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xFB; //设置定时初始值
TH0 = 0xF2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
/******************** 主函数 **************************/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0xff; //设置为推挽输出
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
P00 = 0; //LED Power On
usb_init(); //USB CDC 接口配置
IE2 |= 0X80; //开启USB中断
Timer0_Init(); //定时器0初始化
EA = 1; //开启总中断
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while (1)
{
if (bUsbOutReady)
{
// USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
printf("hello mikeybie\r\n");
usb_OUT_done();
}
//任务3
P0 = ~LED_State[LED_pos];
if(Timer0_cnt[1] >= 1000)
{
Timer0_cnt[1] = 0;
printf("HELLO_AI8051U\r\n");
}
if(Timer0_cnt[0] >= 10)
{
Timer0_cnt[0] = 0;
if(P32 == 0)
{
KEY_press++;
if(KEY_press >= 10)
{
KEY_press = 0;
if(++LED_pos >= 8) LED_pos = 0;
}
}
else
{
KEY_press = 0;
}
}
}
}
void Timer0_Isr(void) interrupt 1
{
for(i=0;i<3;i++)
{
Timer0_cnt[i]++;
}
}


工程中文文件名报错,修改为英文即可。

6.4. 任务四:
任务四是在任务一的基础上加了基于定时器0实现的多任务系统架构,使得代码更加简洁高效。
#include "system.h"
#include "task.h"
/*
b0 b1 b7
低 高
LED0 —— LED7
0 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1
1 1 0 1 1 1 1 1
1 1 1 0 1 1 1 1
1 1 1 1 0 1 1 1
1 1 1 1 1 0 1 1
1 1 1 1 1 1 0 1
1 1 1 1 1 1 1 0
*/
uint8_t LED_State[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//P0 LED控制数组
uint8_t LED_pos = 0;//LED控制数组索引
uint8_t i;
/******************** 主函数 **************************/
void main(void)
{
System_Init();
usb_init(); //USB CDC 接口配置
IE2 |= 0X80; //开启USB中断
Timer0_Init(); //定时器0初始化
EA = 1; //开启总中断
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while (1)
{
if (bUsbOutReady)
{
// USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
printf("hello mikeybie\r\n");
usb_OUT_done();
}
Task_Callback_Handler();
}
}
void Timer0_Isr(void) interrupt 1
{
Task_Run_Time();
}
#include "task.h"
#include "gpio.h"
Task_Struct My_Task[]=
{
{0,10,10,KEY_Task},
{0,300,300,LED0_Blink},
{0,600,600,LED1_Blink},
{0,900,900,LED2_Blink},
};
uint8_t Task_Max = sizeof(My_Task)/sizeof(My_Task[0]);
//任务状态标记函数,放在定时器1ms中断函数里面
void Task_Run_Time(void)
{
uint8_t i;
for(i=0;i<Task_Max;i++)//扫描每一个任务列表
{
if(My_Task[i].tim_cnt)//任务执行周期有值
{
My_Task[i].tim_cnt--;
if(My_Task[i].tim_cnt == 0)//任务执行周期到了
{
My_Task[i].tim_cnt = My_Task[i].tim_newcnt;//重新赋值周期
My_Task[i].task_state = 1;//标记任务可执行状态
}
}
}
}
//任务回调函数处理
void Task_Callback_Handler(void)
{
uint8_t i;
for(i=0;i<Task_Max;i++)
{
if(My_Task[i].task_state)
{
My_Task[i].task_state = 0;
My_Task[i].task_callback();
}
}
}
#include "gpio.h"
uint8_t led0_state=0;
uint8_t led1_state=0;
uint8_t led2_state=0;
uint8_t KEY_press = 0;//按键扫描消抖变量
void LED0_Blink(void)
{
led0_state ^= 1;
P00 = led0_state;
}
void LED1_Blink(void)
{
led1_state ^= 1;
P01 = led1_state;
}
void LED2_Blink(void)
{
led2_state ^= 1;
P02 = led2_state;
}
void KEY_Task(void)
{
if(P32 == 0)
{
KEY_press++;
if(KEY_press >= 10)
{
KEY_press = 0;
printf("按键按下\r\n");
}
}
else
{
KEY_press = 0;
}
}

