小涵子爸爸
发表于 2025-3-30 10:40:21
第八集-定时器周期性调度任务— 实验三:数组法实现LED流水灯
b0 b7
低 高
led0 led7
0 1 1 1 1 1 1 1 0xfe 取反:1 0 0 0 0 0 0 0 0x01
1 0 1 1 1 1 1 1 0xfd 取反:0 1 0 0 0 0 0 0 0x02
1 1 0 1 1 1 1 1 0xfb 取反:0 0 1 0 0 0 0 0 0x04
1 1 1 0 1 1 1 1 0xf7 取反:0 0 0 1 0 0 0 0 0x08
1 1 1 1 0 1 1 1 0xef 取反:0 0 0 0 1 0 0 0 0x10
1 1 1 1 1 0 1 1 0xdf 取反:0 0 0 0 0 1 0 0 0x20
1 1 1 1 1 1 0 1 0xbf 取反:0 0 0 0 0 0 1 0 0x40
1 1 1 1 1 1 1 0 0x7f 取反:0 0 0 0 0 0 0 1 0x80
#include"ai8051u.h"
#include"ai_usb.h"
#define MAIN_FOSC24000000UL
u8 i = 0;
u16 count_ms = 0;
u8 state={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void Timer0_Init(void);
void main()
{
EAXFR = 1;
WTST = 0;
CKCON = 0;
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
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; //设置为准双向口
usb_init();
EUSB = 1;
Timer0_Init();
EA = 1;
while (DeviceState != DEVSTATE_CONFIGURED);
P40 = 0; // 打开LED供电
while(1)
{
if (bUsbOutReady)
{
usb_OUT_done();
}
if(count_ms>=500)
{
count_ms = 0;
P0 = ~state; //此处i取值0-7
i++;
if(i>7)//边界判断
{
i = 0;
}
}
}
}
void Timer0_Isr(void) interrupt 1
{
count_ms++;
}
void Timer0_Init(void) //1毫秒@24.000MHz
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初始值
TH0 = 0xA2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
小涵子爸爸
发表于 2025-3-30 11:06:31
第八集-定时器周期性调度任务— 实验四:利用数组法点亮LED实现流水灯,每按一次按键,LED右移一位。同时执行任务2:串口每秒钟打印字符串
#include"ai8051u.h"
#include"ai_usb.h"
#define MAIN_FOSC24000000UL
u8 i = 0;
u8 num = 0;
u16 key_vol = 0;
u16 count_ms ={0, 0};
u8 state={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void Timer0_Init(void);
void main()
{
EAXFR = 1;
WTST = 0;
CKCON = 0;
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
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; //设置为准双向口
usb_init();
EUSB = 1;
Timer0_Init();
EA = 1;
while (DeviceState != DEVSTATE_CONFIGURED);
P40 = 0; // 打开LED供电
while(1)
{
if (bUsbOutReady)
{
usb_OUT_done();
}
P0 = ~state;
if(count_ms>=1000)
{
count_ms = 0;
printf("STC TEST\r\n");
}
if(count_ms>=10)
{
count_ms = 0;
if(P32 == 0)
{
key_vol++;
if(key_vol==5)
{
num++;
if(num>7)
{
num = 0;
}
}
}
else
{
key_vol = 0;
}
}
}
}
void Timer0_Isr(void) interrupt 1
{
for(i=0;i<2;i++)
{
count_ms++;
}
}
void Timer0_Init(void) //1毫秒@24.000MHz
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初始值
TH0 = 0xA2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
小涵子爸爸
发表于 2025-4-6 14:39:16
第八集-定时器周期性调度任务— 实验五:利用结构体及函数指针实现多任务处理及函数调用
void LED0_Blink(void)
{
State1 = !State1;
P00 = State1;
}
void LED1_Blink(void)
{
State2 = !State2;
P01 = State2;
}
void LED2_Blink(void)
{
State3 = !State3;
P02 = State3;
}
void Key_Task(void)
{
if(P32 ==0 )
{
Key_Vol++;
if(Key_Vol == 5)
{
printf("按键P32按下");
}
}
else
{
Key_Vol = 0;
}
}
-----------------------------------------------------------
typedef struct
{
u8 Run; //任务状态:Run/Stop
u16 TIMCount; //定时计数器
u16 TRITime; //重载计数器
void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
-------------------------------------------------------------
static TASK_COMPONENTS Task_Comps[]=
{
//状态计数周期函数
{0,250,250,LED0_Blink},
{0,500,500,LED1_Blink},
{0,1000,1000,LED2_Blink},
{0,10,10,Key_Task},
};
-------------------------------------------------------------
void Task_Pro_Handler_Callback(void)
{
u8 i;
for(i=0;i<Task_Max;i++)
{
if(Task_Comps.Run)
{
Task_Comps.Run = 0;
Task_Comps.TaskHook();
}
}
}
小涵子爸爸
发表于 7 天前
第九集-数码管— 实验一:使用74HC595静态显示1位数字
8位共阴数码管断码表:
u8 SEG_NUM[]=//8位共阴数码管-断码表
{
0x3F, /*'0', 0*/
0x06, /*'1', 1*/
0x5B, /*'2', 2*/
0x4F, /*'3', 3*/
0x66, /*'4', 4*/
0x6D, /*'5', 5*/
0x7D, /*'6', 6*/
0x07, /*'7', 7*/
0x7F, /*'8', 8*/
0x6F, /*'9', 9*/
0x77, /*'A', 10*/
0x7C, /*'B', 11*/
0x39, /*'C', 12*/
0x5E, /*'D', 13*/
0x79, /*'E', 14*/
0x71, /*'F', 15*/
0x40, /*'-', 16*/
0x00, /*' ', 17*/
0x80, /*'.', 18*/
};
/**************** HC595初始化函数 ******************/
void Init_595(void)
{
HC595_SER = 0;
HC595_RCK = 0;
HC595_SCK = 0;
}
/**************** 向HC595发送一个字节函数 ******************/
void Send_595(u8 dat)
{
u8i;
for(i=0; i<8; i++)
{
dat <<= 1;
HC595_SER = CY;
HC595_SCK = 1;
HC595_SCK = 0;
}
}
/********************** 显示扫描函数 ************************/
void Display_Seg(u8 HC595_1,u8 HC595_2)
{
Send_595(HC595_1); //数码管段码输出高电平点亮
Send_595(HC595_2); //数码管位码 低电平点亮
HC595_RCK = 1;
HC595_RCK = 0;
}
void Seg_Task(void)
{
Display_Seg(SEG_NUM,~T_NUM);
}
小涵子爸爸
发表于 7 天前
第九集-数码管— 实验二:显示123456789
u8 T_NUM=
{
0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80//为了方便书写及计算,后面还会再取反
};
u8 Seg_no = 0;
void Seg_Task(void)
{
Display_Seg(SEG_NUM,~T_NUM); //逐个点亮8个数码管
Seg_no++;
if(Seg_no >7)
{
Seg_no = 0;
}
}
小涵子爸爸
发表于 7 天前
第九集-数码管— 实验三:显示00-00-00并走秒
u8 Seg_no = 0;
u8 shi = 0;
u8 fen = 0;
u8 miao = 0;
void Seg_Task(void)
{
u8 num = 0;
if( Seg_no ==0 ) //小时十位
{
num = shi/10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==1 ) //小时的个位
{
num = shi%10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==2 ) //第一个横杠
{
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==3 ) //分钟的十位
{
num = fen/10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==4 ) //分钟的个位
{
num = fen%10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==5 ) //第二个横杠
{
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==6 ) //秒的十位
{
num = miao/10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else if( Seg_no ==7 ) //秒的个位
{
num = miao%10;
Display_Seg( SEG_NUM , ~T_NUM); //数码管刷段码和位码
}
else
{
}
Seg_no++;
if(Seg_no >7)
{
Seg_no = 0;
}
}
void TIMECOUNT_Task(void)
{
miao ++;
if( miao>59 )
{
miao = 0;
fen++;
if( fen>59 )
{
fen = 0;
shi ++;
if( shi>23 )
shi = 0;
}
}
}
小涵子爸爸
发表于 3 天前
第十二集-系统复位— 实验一:看门狗
WDT_CONTR = 0x24;//启动看门狗,32分频,24M主频下约0.5秒
if(P33!=0)//如果P33按下超过0.5秒,则系统复位
{
WDT_CONTR = 0x34;//看门狗定时器CLR_WDT清0,俗称“喂狗”
}
至此,复位后数码管显示乱码,且无法再次使用CDC不停电下载。在系统初始化函数中增加以下代码后恢复正常:
void USB_Reset_U(void)
{
P3M0 = 0x00;
P3M1 = 0x00;
P3M0 &= ~0x03;
P3M1 |= 0x03;
USBCON = 0X00;
USBCLK = 0X00;
IRC48MCR = 0X00;
Delay10ms();
}
小涵子爸爸
发表于 3 天前
第十三集-外部中断— 实验一:INT1中断
void INT1_Init(void)
{
IT1 = 1;//下降沿中断
EX1 = 1;//打开中断允许
//EA =1;
}
void INT1_Isr(void) interrupt 2
{
LED_State = ~LED_State;//LED状态取反
P0 = LED_State;
}
小涵子爸爸
发表于 3 天前
第十四集-IO中断— 实验一:使用P33验证下降沿中断
void P3_IO_Inter_Init(void)
{
P3IM0 = 0x00;
P3IM1 = 0x00; //设置下降沿中断
P3INTE = 0x08; //使能P33口中断
}
void P3_Inter_Isr(void) interrupt 40
{
P3INTF = 0x00;//将中断标志位手动清零
LED_State = ~LED_State;//LED状态取反
P0 = LED_State;
}
使用IO中断最重要的是注意,因P3端口中断号40超过31,编译前运行使用官方提供的拓展Keil的C代码中断号工具。
小涵子爸爸
发表于 3 天前
第十二集-系统复位— 实验二:软件复位
IAP_CONTR = 0X20; //复位到用户程序区
IAP_CONTR = 0X28; //复位到用户系统区
IAP_CONTR = 0X60; //复位到系统ISP区
经测试也需配合USB_Reset_U()程序一起使用