找回密码
 立即注册
楼主: njslmcc

学习心得

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2025-09-17 00:55:10
已绑定手机

1

主题

14

回帖

107

积分

注册会员

积分
107
发表于 前天 07:03 | 显示全部楼层
第八集 定时器周期性调度任务 学习笔记

如何修正编译错误,
ISP更多设置,分包时间显示与否

一、用期性任务介绍
任务1:用一个定时器实现这个任务。LED1实现0.3秒取反一次,LED2实现06秒取反一次,LED3实现0.9秒取反一次
数组使用分两步:
1、定义:类型 名称[长度] = {数值};
2、使用:赋值:名称[索引] = 数值

任务2:数组点亮LED,实现流水灯
注意事项:LED是0亮1灭,数组长度要把握好,流水灯移动的时间
变量定义
        u8 State[8]   = {0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
核心代码
        if(Count_ms[0]>=500)
        {            
                Count_ms[0] = 0;
                P0 = ~State[num];   //num 取值0-7
                num++;
                if(num>7) num=0;
        }

任务3:按键1按一下,LED通过数组移动一下
注意事项:按键不能再通过while判断是否按下松开了,可以通过按键按下计数
变量定义
        u16 Key_Vol = 0;                 //按键按下持续时间
核心代码
        P0 = ~State[num];              //num 取值0-7
      
        if(Count_ms[1]==1000)       //1000ms执行一次
        {
                Count_ms[1] = 0;
                printf("Ai8051u\r\n");
        }
        
        if(Count_ms[2]==10)             //10ms执行一次
        {
                Count_ms[2] = 0;
                if(P32 == 0)                 //按键按下
                {
                        Key_Vol ++;
                        if(Key_Vol==5)      //按键按下
                        {
                                num ++;
                        }
                }
                else
                {
                        Key_Vol = 0;
                }
       }

二、文件的创建(.c和.h)
创建程序文件三步,把硬件需要的初始化做一个config.c
新建文件并保存,添加到工程,添加到引用路径
一般一个.c和一个.h文件,执行一个外设或者一个任务或功能,这样可以让代码看起来简洁明了

新建XXX.c和XXX.h文件,代表一个功能块,
XXX.h格式:
#ifndef __XXX_H
#define __XXX_H
调用头文件
函数声明,
#endif

XXX.C格式
#inlude “XXX.H”
函数定义
添加文件一定要记得引用路径和添加一工程里。

三、结构体的介绍


四、结构体数组的周期性任务调度
LED1   0.3秒闪一次,
LED2   0.6秒闪一次,
LED3   0.9秒闪一次
1、都有定时器1ms加的变量
2、都有一定设定的计数目标
3、都有需要执行的功能
4、定时时间到了才能执行

typedef struct
{
        u8   Run;                                // 任务状态,Run/Stop
        u16 TIMCount;                        // 定时器计数器
        u16 TRITime;                          // 重载计数器
        void (*TaskHook)(void);           //任务函数
}TASK_COMPONENTS;

任务4:按键1按一下,LED通过数组移动一下,用虚拟LED显示
思路:
变量定义
u8 State[8]   = {0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};        //事先编排好
u8 Key_Vol[2] = {0, 0};

核心代码
void Key_Task(void)
{
        if (P32 == 0)
        {
                Key_Vol[0]++;               

                if (Key_Vol[0]==5)
                {
                        //按键按下的任务
                        P0 = ~State[Key_Vol[1]];
                        Key_Vol[1]++;  
                }
        }
        else
        {
                Key_Vol[0] = 0;
        }
}

简易舞台灯光控制系统:
1、按下按钮1,一键启动或关闭LED动作
2、启动后电脑上的LED开始工作
P0口的LED灯循环往下移动
P2口的LED灯循环往上移动
P4口的LED高四位和低四位交替闪烁
P1口的8个LED灯全亮或全灭交替(P1.2的位置用P5.2代替)

在Task.c 中写上如下任务表:
TASK_COMPONENTS Task_Comps[]=
{
        //状态  计数    重载数   函数
        {0,       10,      10,       Key_Task},                  /* task 1 Period: 10ms */
        {0,       100,    100,     LED1_Task},                /* task 2 Period: 100ms */
        {0,       200,    200,     LED2_Task},                /* task 3 Period: 200ms */
        {0,       300,    300,     LED3_Task},                /* task 4 Period: 300ms */
        {0,       400,    400,     LED4_Task},                /* task 5 Period: 400ms */
};

在io.c中写上:

//按下按钮1,一键启动或关闭LED动作
u8 Stage1 = 0;      //LED的初值,LED可以为P3上的一个口
u8 Key_Vol = 0;

void Key_Task(void)
{
        if (P32==0)
        {
                Key_Vol++;
                if (Key_Vol==5)
                {
                        //按键按下的任务
                        Stage1 = !Stage1;
                        LED0 = Stage1;   
                }         
        }
        else
        {
                Key_Vol = 0;
        }
}

// P0口的LED灯循环往下移动
u8 Stage2 = 0;      //初值
u8 LED1[8] = {0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}

void LED1_Task(void)
{
        P0 = ~LED1(Stage2);
        Stage2++;
        if (Stage2>7)  Stage2 = 0;  
}

// P2口的LED灯循环往上移动
u8 Stage3 = 0;      //初值
u8 LED2[8] = {0x80,0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}

void LED2_Task(void)
{
        P2 = ~LED2(Stage3);
        Stage3++;   
        if (Stage3>7)  Stage3 = 0;  
}

// P4口的LED高四位和低四位交替闪烁
u8 Stage4 = 0;  //初值
u8 LED4[2] = {0x0f, 0xf0}

void LED3_Task(void)
{
        P4 = LED4(Stage4);
        Stage4++;   
        if (Stage4>1)  Stage4 = 0;  
}

// P0 P1口的8个LED灯全亮或全灭交替(P1.2的位置用P5.2代替)
u8 Stage5 =0;  //初值
u8 LED5[2] = {0x00,0xff}

void LED4_Task(void)
{
        P0 = P1 = LED5(Stage5);   //(P1.2的位置用P5.2代替)怎么实现?
        Stage5++;  
        if (Stage5>1)  Stage5 = 0;  
}

在io.h中写上
void Key_Task(void);
void LED1_Task(void);
void LED2_Task(void);
void LED3_Task(void);
void LED4_Task(void);

这一课的内容很有用,再遇到类似的多任务,只要做好如下3步:
1、在Task.c的列表中按“状态,计数,重载数,函数”的格式加上新的任务,
2、在io.c中写好函数
3、在io.h中登记一下


回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:16
  • 最近打卡:2025-09-17 00:55:10
已绑定手机

1

主题

14

回帖

107

积分

注册会员

积分
107
发表于 3 小时前 | 显示全部楼层
第九集 数码管 学习笔记

擎天柱交流网址:https://www.stcaimcu.com/thread-11902-1-1.html
里面会有注意事项及常见编程错误等信息

一、数码管介绍
本质都是LED,类型分共阴共阳,74HC595

二、数码管显示原理
显示段码,位码,总显示时间不能大于20ms

三、数码管静态显示

任务1:在第一位上显示0
在任务列表中加入
   {0,  1,    1,     Seg_Task},  

在io.c中加入代码:

u8 SEG_NUM[]=
{
    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*/
};

u8 T_NUM[8] =
{
    0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80
};

void Init_595(void)
{
    HC595_SER = 0;
    HC595_RCK = 0;  
    HC595_SCK = 0;
}

/************向HC595发送一个字节函数************/

void Send_595(u8 dat)
{
    u8 i;
   
    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;   
}   

u8 Seg_no = 0;

void Seg_Task(void)
{
    Display_Seg( SEG_NUM[0], ~T_NUM[0]);
}

在io.h中增加如下定义:
#define HC595_SER         P34
#define HC595_RCK         P35
#define HC595_SCK         P32

void Init_595(void);
void Send_595(u8 dat);
void Display_Seg(u8 HC595_1, u8 HC595_2);
void Seg_Task(void);

就可以在第一位显示出“0”了。

四、        数码管动态显示

任务2,显示12345678
只要改写下列函数
void Seg_Task(void)
{
    Display_Seg( SEG_NUM[Seg_no+1], ~T_NUM[Seg_no]);     //刷段码和位码
    Seg_no++;
    if(Seg_no>7)
        Seg_no = 0;
}

任务3,按00-00-00的格式显示时分秒
在任务列表中加入
   {0, 1000,  1000,  TIMECOUNT_Task}, /* task 5 Period: 1000ms */  

在io.c中加入代码
u8 shi  = 0;
u8 fen  = 0;
u8 miao = 0;

void TIMECOUNT_Task(void)
{
    miao ++;
    if( miao>59 )
    {
        miao = 0;
        fen++;
        if( fen>59 )
        {
            fen = 0;
            shi ++;
            if( shi>23 )
                shi = 0;
        }
    }
}

void Seg_Task(void)
{
    for(i=0;i<8;i++)
    {
        //算出每一位的值并显示出来
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    Seg_no++;
    if(Seg_no>7)
        Seg_no = 0;
}

在io.h中增加如下定义:
void TIMECOUNT_Task(void);

就能在LED上显示时分秒了

五、虚拟显示—LED和数码管
(有空的时候可以看一下)

课后小练习

简易10秒免单计数器,
1、在前四位数码管上显示目标时间,即“10.00”表示定时时间10秒钟
2、后四位显示当前的计时00.00,最小单位为10ms
3、按下开始按钮后,每10ms最末尾的数字+1,直到按下结束按钮后停止计数。

在任务表添加两个任务
   {0,  1,    1,     Seg_Task},      
   {0, 10,  10,  TIMECOUNT_Task},

在io.c中加入如下代码:

U16 js = 0;
U8 flag=0;

void TIMECOUNT_Task(void)
{
    If(flag==0)
        js ++;
    if(P32==0)
        flag=1;
}

void Seg_Task(void)
{
    if(Seg_no==0)
    {
        num = 1;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==1)
    {
        num = 0;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==2)
    {
        num = 0;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==3)
    {
        num = 0;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }

    else if(Seg_no==5)
    {
        num = js/1000;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==6)
    {
        num = (js%1000)/100;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==7)
    {
        num = (js%100)/10;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }
    else if(Seg_no==8)
    {
        num = js%10;
        Display_Seg( SEG_NUM[num], ~T_NUM[Seg_no]);
    }

    Seg_no++;
    if(Seg_no>7)
        Seg_no = 0;
}

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-9-17 09:36 , Processed in 0.131922 second(s), 51 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表