小涵子爸爸 发表于 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()程序一起使用

页: 1 [2] 3
查看完整版本: Ai8051U学习打卡记录贴