桃花飞舞 发表于 2025-2-15 16:39:40

第六课IO输入输出
变量取反
u8 state = 0;
//任务1:按下P32按钮灯亮,松开P32按钮灯灭;
if( P32 == 0 )      //判断P32按键是否被按下
{
      P00 = 0;
}
else
{
      P00 = 1;
}

//任务2:按下P32按钮灯灭,松开P32按钮灯亮;
if( P32 == 1 )      //判断P32按键是否被按下
{
      P00 = 0;
}
else
{
      P00 = 1;
}

//任务3:按一下灯亮,按一下灯灭
if ( P32 == 0 )
{
      Delay20ms();                                                      //延时20ms消抖
      if (P32 == 0)               
      {               
                state = !state;               
                P00 = state;                                                //变量取反0 1 0 1 0
                printf("state: %d\r\n", (int)state);

                while(P32 == 0);                              //等待P32松开
      }
}

GPIO的介绍拉电流和灌电流,高低电平电压的介绍,按键原理和按键抖动的介绍
delay()函数是CPU停在这里不会往下走,这是一个很非内存的做法

桃花飞舞 发表于 2025-2-15 18:35:07

第七节课定时器中断
void Timer0_Init(void)                //3秒@24.000MHz
{
        TM0PS = 0x5B;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0x3F;                                //设置定时初始值
        TH0 = 0x01;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时

//        TM0PS = 0x5B;91
//12T   /12
// TH0 - TL0 = 319
}

void Timer0_Isr(void) interrupt 1   //3秒执行一次
{
        state = !state;
        P00 = state;

}
int count;                //按键计数变量

if ( P32 == 0 )
{
        Delay20ms();                                                        //延时20ms消抖
        if (P32 == 0)               
        {               
                printf("按键按下次数\xfd: %d\r\n", (int)count);
                count++;

                while(P32 == 0);                                //等待P32松开
        }
}

定时频率(HZ) = Sysclk(hz)/((TM0PS + 1)*(65536-)*T)
定时时间(s) = ((TM0PS + 1)(65536-)*T)/Sysclk(hz)
= 65536-(Sysclk(hz) * 定时时间(s))/(T*(TM0PS + 1))
T = 1或者12.
16位自动重载定时器的本质就是从设定值数到65536(溢出)之后置位一次标志位,如果使能ET0就可以进入中断!

返回值类型 函数名(入口参数)
{
        //函数体
        //函数执行的代码
        return 返回值;
}
函数的定义、声明、调用
定义:包含返回值,函数名和入口参数,并定义了函数 具体功能

函数的名称应当能够描述函数的功能,便于代码的阅读和理解.
函数名称应当使用有意义的英文单词或者组合的英文单词,避免使用特殊字符或数字。
函数名称不能与C语言的关键字同名。例如if等

返回值类型 函数名(入口参数);
声明: 在头文件或者被调用之前使用,注意末尾要加分号

函数名(入口参数);
调用:在需要调用的地方直接使用函数名,加上括号和分号。
如果有入口参数的,需要在括号的多个参数之间加逗号隔开。
int count;                //按键计数变量
//任务2:灯按一下点亮三秒后熄灭
if ( P32 == 0 )
{
        Delay20ms();                                                        //延时20ms消抖
        if (P32 == 0)               
        {               
//                printf("按键按下次数\xfd: %d\r\n", (int)count);
//                count++;
                P00 = 0;
                Timer0_Init();


                while(P32 == 0);                                //等待P32松开
        }
}


void Timer0_Isr(void) interrupt 1   //3秒执行一次
{
//        state = !state;
        P00 = 1;
        TR0 = 0;                //定时器0关闭
}


void Timer0_Init(void)                //500毫秒@24.000MHz
{
        TM0PS = 0x0F;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0xDC;                                //设置定时初始值
        TH0 = 0x0B;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
}

int count;                //按键计数变量
u8 state = 0;                        //初始状态
u8 Run_State = 0;        //运行状态
//任务3:救护车灯控制器,按下报警按钮,红蓝灯交替闪烁(LED1和LED2表示红和蓝灯),再按一下报警按钮,红蓝灯停止。
if ( P32 == 0 )
{
        Delay20ms();                                                        //延时20ms消抖
        if (P32 == 0)               
        {               
                Run_State = !Run_State;                        //运行状态取反

                if ( Run_State == 1)
                {
                        Timer0_Init();
                }
                else
                {
                        TR0 = 0;                //关闭定时器
                        P00 = 1;
                        P01 = 1;
                }
//                P00 = 0;
//                Timer0_Init();
                while(P32 == 0);                                //等待P32松开
        }
}


void Timer0_Isr(void) interrupt 1   //500ms执行一次
{
        state = !state;

        P00 = state;
        P01 = !state
}



定时器一次只能定时一次,如果我有很多个定时任务怎么办?
前后台的方法,用定时器做心跳2.5ms, 在中断中把HeartBeat = 1,,while(1) { if (HeartBeat) { HeartBeat = 0;}}根据定时任务的定时时间来执行,也就是说如果a任务是1s执行一次,if (count1S++>= 400)执行一次a任务count1S = 0;任务b是10s执行一次,if( count10S++ >= 4000) 执行一次任务b

白水大虾2016 发表于 2025-2-15 20:43:32

今天继续矩阵

白水大虾2016 发表于 2025-2-16 13:07:13

今天继续矩阵按键,有些地方搞不清转不过弯啊!

桃花飞舞 发表于 2025-2-16 13:35:48

第八节定时器周期性任务调度
这节课的代码太多我就不一一贴出来了,而且实现的任务比较多。
单片机型号错误 可以手动选择AI8051u-34K64, 或自动检测。
多任务,
任务调度系统,定时器驱动的所以时间会特别的准
周期性的多任务
手打实现三个任务,然后又讲了config.c config.h文件的固定格式,最后引入的任务调度系统,这个任务调度系统和前面三个任务实现的功能是基本一样的但是代码得到了精简和优化。这个任务调度系统模版更容易后期的维护,系统结构更加清晰,便于分层设计、利于系统抽象。

桃花飞舞 发表于 2025-2-16 16:57:00

小陈数码 发表于 2025-2-16 14:19
我这一节看了好次。

是的,一开始看任务调度系统我也是懵逼。特别是里面结构体和函数指针,后面多看几遍发现也不是不能看懂,别误解了它,觉得很难,我是想听听不同的人讲这部分知识,跟着做一遍例程。
冲哥一开始手打实现的三个任务相当于是前后台,前台就是while(1),里面的代码,后台是定时器给变量计数。
周期性裸机的任务调度框架,应用/业务层 、 平台驱动层, 这种软件架构更优秀。

engusizy 发表于 2025-2-16 19:45:44

支持支持{:4_174:}

hsecyxg 发表于 2025-2-16 22:19:23

桃花飞舞 发表于 2025-2-16 16:57
是的,一开始看任务调度系统我也是懵逼。特别是里面结构体和函数指针,后面多看几遍发现也不是不能看懂,别 ...

这个多任务调度系统的编辑思路很精妙,但实际应用有两点不好把握:1.属性相似的任务会相冲突。2.动态刷新和运行周期不好把握,这一点需要反复调试才能掌握。

蓝鹰 发表于 2025-2-17 08:13:24

{:qiang:}

psp51371 发表于 2025-2-17 09:39:16

太强悍了,从当年的STC89C52,到STC12,到STC15,到现在的AI8051,在追赶科技的道路上我们一直在奔跑!!!
页: 67 68 69 70 71 72 73 74 75 76 [77] 78 79 80 81 82 83 84 85 86
查看完整版本: 《8051U深度入门到32位51大型实战视频》,【免费 + 包邮 送】实验箱@Ai8051U,100万套