dumon 发表于 2024-2-28 10:22:32

电路中常见的上拉电阻与下拉电阻是什么意思?今天就来讲一下。


上拉的意思就是IO口通过串联1个电阻(一般为5K或10K)与VCC相连接,IO口为高电平状态,上就是电压往上的意思。
下拉的意思就是IO口通过串联1个电阻(一般为5K或10K)与GND相连接,IO口为低电平状态,下就是电压往下的意思。


大家想想看,为什么要串联1个电阻,在后面的图片会有说明。


当然冲哥视频讲了,高低电平只是1个电压范围,并不是具体到某一数值,如:0~1.8V范围内我们都可以认为是低电平,4.5~5.5V范围内我们可以认为是高电平。
这里也提下醒,不同的电子设备也许都支持串口通讯,但是他们的VCC也可能不一样,比如5V的MCU和3.3V的MCU都支持串口通讯,但是他们的RX,DX电平可能
不一样,5V的MCU我们需要将其RX,DX降压到3.3V后才能与3.3V的MCU进行信息通讯。这里特别提醒下就是这个意思。

附个图吧,看过这个图后就知道电路中说的上拉和下拉是什么意思了,以后在电子设计中假如需要保持某个IO上电后上拉或下拉就能知道了,这也是一个非常重要的知识点。

dumon 发表于 2024-3-7 18:24:20

第7集 按键点灯



本章是主要介绍按键的一些常用功能,按键我们按功能分为自复位和自锁型,按按键状态我们又分为常开型和常闭型。按键在电路中主要分为0或1,即表示断开或接通。
自复位——不能保持按键状态,必须一直按住才能保持状态,松手后按键回复为初始状态。
自锁型——可以保持按键状态,只需按下一次后松手可以维持状态,再次按下后又回复到初始状态。
常开型——未按下时为断开状态,按下后为接通。
常闭型——未按下时为接通状态,按下后为断开。


正常我们的按键都是机械按钮,可以理解为是一个金属弹片,就像冲哥视频里说的,机械按钮在接触的一瞬间ms级别,电平会发生上下变化,这个时候检测电平是不准确的,
我们必须等弹片完全接触好后再去读取引脚电平,这个延时过程我们称之为消抖。


像我平时工作时有接触到PLC,PLC里面有2个指令,是脉冲上升沿触发和脉冲下降沿触发,我觉得跟本集按键点灯里有很多功能类似。


脉冲上升沿是指信号从0变为1的瞬间去执行指令,而脉冲下降沿触发是指信号从1变为0的瞬间去执行指令,必须有这个0变为1或1变为0的切换过程。

冲哥是使用STC32G实验箱来做实验的,正常P3.2和P3.4.P3.5都是上拉到5V,即正常情况下为1,按键按下为变为0.


这里要注意一下,在按键消抖后,有动作执行语句和while(),此两者的顺序不一样,得到的结果也不一样。比如:
1.将while()放到动作执行语句之前,那么在你没有松开按键前,是不是整个语句都被while()按在这里了,只有当你松开按键是不是才能执行动作语句。
那这个按键未按下前为1,按下后为0,再次松开为1,是不是我们就是卡的这个0转为1的上升沿才执行动作语句。
2.那假如把while()放到动作执行语句之后,是不是我们只要满足按键消抖后就会立刻执行完动作语句,但如果你一直不松按键,是不是就会被后面的while()按在这里了。
那这个按键未按下前为1,按下后为0,是不是我们就是卡的这个1转为0的上升沿才执行动作语句。

至于为什么加while(),是因为我们只想让这个动作执行一次,避免多次执行。

while的顺序需要你根据自己的实际需要来放置位置,比如你需要按钮按下立刻执行,就把动作语句放到while()之前,
如果你想按钮按下待松开后才执行,就把动作语句放于while()之后,这样只有松开按钮后才能跳出循环执行动作语句。我称之为滞后性。

至于按键循环按动,每次按下都切换状态,这也是很简单的,就是对P口取反。或者用1个状态变量,每次按下都把状态变量去取反。这样是不是就可以实现1个按钮来控制
电机启停了。这在PLC也是一个经典的案例,单按钮启停。从这里也能找到对照哦。

这个代码我是有照着冲哥视频做了一遍,自己根据不同的方法又做了一遍,通过交叉对比加深自己的认识。
88

/***********************************************************************
        第7集 按键点灯(实操)
1.P3.3按键按下P2.0上的LED点亮,松开熄灭
2.P3.4按键按下P2.7上的LED熄灭,松开点亮
3.P3.5按键按下一次,P2.1上的LED状态改变一次
4.P3.3按键按下一次,LED往左边走一个,P3.5按键按下一次,LED往右边走一个,

***********************************************************************/

#include <STC32G.H>
#include "comm/stc32_stc8_usb.h"

#define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void sys_init();


void delay_ms(u16 ms);

sbit button_P33 = P3^3 ;                                // 按键P3.3,上拉到5V
sbit button_P34 = P3^4 ;                                // 按键P3.4,上拉到5V
sbit button_P35 = P3^5 ;                                // 按键P3.4,上拉到5V

sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
sbit LED20 = P2^0 ;                                                // P2.0上的LED
sbit LED21 = P2^1 ;                                                // P2.1上的LED
sbit LED27 = P2^7 ;                                                // P2.7上的LED

bit buttonState ;                                                // 布尔变量存储按键状态

void main()
{
        sys_init();//系统初始化
    usb_init();//USB CDC 接口配置
    EA = 1;       
       
        LEDON = 0 ;
        P2 = 0xFE ;
       
        while(1)
        {
// 1.P3.3按键按下P2.0上的LED点亮,松开熄灭               
                if(button_P33 == 0)
                {
                        delay_ms(10);
                        while(button_P33 == 0)
                        {
                                LED20 = 0 ;
                        }
                        LED20 = 1;
                }
               
// 2.P3.4按键按下P2.7上的LED熄灭,松开点亮
                if(button_P34 == 0)
                {
                        delay_ms(10);
                        while(button_P34 == 0)
                        {
                                LED27 = 1 ;
                        }
                        LED27 = 0;
                }

// 3.1 P3.5按键按下一次,P2.1上的LED状态改变一次
                if(button_P35 == 0)
                {
                        delay_ms(10);
                        if(button_P35 == 0)
                        {
                                while(button_P35 == 0)
                                {
                                        LED21 = buttonState ;
                                }
                                buttonState = !buttonState ;
                        }
                }
               
// 3.2 P3.5按键按下一次,P2.1上的LED状态改变一次,按下后立刻执行
//                if(button_P35 == 0)
//                {
//                        delay_ms(10);
//                        if(button_P35 == 0)
//                        {
//                                LED21 = !LED21 ;
//                                while(button_P35 == 0);
//                        }
//                }

// 3.3 P3.5按键按下一次,P2.1上的LED状态改变一次,教材中冲哥的方法,松开按键后执行,滞后性
//                if(button_P35 == 0)
//                {
//                        delay_ms(10);
//                        if(button_P35 == 0)
//                        {
//                                while(button_P35 == 0);                               
//                                LED21 = !LED21 ;

//                        }
//                }               

// 4.P3.3按键按下一次,LED往左边走一个,P3.5按键按下一次,LED往右边走一个,
//                if(button_P33 == 0)
//                {
//                        delay_ms(10);
//                        if(button_P33 == 0)
//                        {
//                                P2 = (P2<<1)+1;                                // LED往左移动1个
//                                while(button_P33 == 0);                // 检测到按键未释放时,停留在此步
//                                if(P2 == 0xFF)                                // 当最左边LED点亮时,切换到最右边LED
//                                {
//                                        P2 = 0xFE;
//                                }
//                        }
//                }
//                if(button_P35 == 0)
//                {
//                        delay_ms(10);
//                        if(button_P35 == 0)
//                        {
//                                P2 = (P2>>1)|0x80;                        // LED往右移动1个
//                                while(button_P35 == 0);                // 检测到按键未释放时,停留在此步
//                                if(P2 == 0xFF)                                // 当最右边LED点亮时,切换到最左边LED
//                                {
//                                        P2 = 0x7F;
//                                }
//                        }
//                }
        }
}

void delay_ms(u16 ms)
{
        u16 i;       
        do
        {
                i = MAIN_Fosc/6000;
                while(--i);
        } while(--ms);
}

void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    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 初始化 ======
    P3M0 &= ~0x03;
    P3M1 |= 0x03;
   
    IRC48MCR = 0x80;
    while (!(IRC48MCR & 0x01));
}



dumon 发表于 2024-3-9 20:03:38

第8集 蜂鸣器的应用

    本集是在前面按键点灯的基础上,对按键应用的一次拓展,这里牵涉到多个按键一起工作,如何处理好这些按键的功能,按键的先后对程序有无影响,了解动作流程,并针对程序运行实际效果对程序进行修改是本集重点。


先来看下程序要求:

1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。

开发板:STC32G自制开发板
IO分配:
LED1~8:P2口,控制P2口点灯的是P4.5引脚,即P4.5为0,P2口输出0才能点亮LED,
按键1:P33,按键2:P34
蜂鸣器:P5.4

按键优先级:按键1高于按键2,因为按键1必须先按下工作后,按键2才能工作,同时按键1只要按下,所有LED全部熄灭,代表按键2的功能也停止,这里一定要理解。
同时我们在程序编写时要考虑一些特别情况,比如说按键1我按下一直不松,会不会一直循环开机关机之类。

这里我用的是跟冲哥不一样的思路,我在学习的时候我都会先不看冲哥的编程,而是自己先思考一遍,自己根据前面所学我是否能独立的把这个程序编辑出来,如果想不通再去参考下冲哥和程序思路,这样可以做到举一反三,拓展自己的处理问题的方式。
下面请看我自己所编写的程序,经过实测可以达到程序要求的功能。具体介绍都在程序注释内,希望能给朋友们一些启发。
开发板放在公司里了,没有及时用相机拍下程序运行的画面,待周一补上吧。


/***********************************************************************
        第8集 蜂鸣器实战应用(实操)
1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。

***********************************************************************/

#include <STC32G.H>
#include "comm/stc32_stc8_usb.h"

#define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void sys_init();

void delay_ms(u16 ms);
void BEEP_on(u16 ms);
void On_Off_Blinker(u16 ms,u8 times);

sbit button_P33 = P3^3 ;                                // 按键1 上电后是上拉到5V,开关按下是下拉到0V
sbit button_P34 = P3^4 ;                                // 按键2 上电后是上拉到5V,开关按下是下拉到0V

sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
sbit LED20 = P2^0 ;                                                // P2.0上的LED
sbit LED21 = P2^1 ;                                                // P2.1上的LED
sbit LED22 = P2^2 ;                                                // P2.2上的LED
sbit LED23 = P2^3 ;                                                // P2.3上的LED
sbit LED24 = P2^4 ;                                                // P2.4上的LED
sbit LED25 = P2^5 ;                                                // P2.5上的LED
sbit LED26 = P2^6 ;                                                // P2.6上的LED
sbit LED27 = P2^7 ;                                                // P2.7上的LED

sbit BEEP = P5^4;                                                // 蜂鸣器

bit buttonState ;                                                // 布尔变量存储按键状态

u8 a;                                                                        // LED数组索引号

u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms

u16 on_led_blinker_time = 200;                        // 开机LED点亮时间200ms
u16 of_led_blinker_time = 500;                        // 关机LED点亮时间500ms
u8on_led_blinker_times = 1;                        // 开机LED闪烁次数1次
u8of_led_blinker_times = 3;                        // 关机LED闪烁次数3次

u8 LED = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,0x00,0xFF };                                                // 数组用于记录8个LED灯
// 1111 1110 0xFE;
// 1111 1101 0xFD;
// 1111 1011 0xFB;
// 1111 0111 0xF7;
// 1110 1111 0xEF;
// 1101 1111 0xDF;
// 1011 1111 0xBF;
// 0111 1111 0x7F;

void main()
{
        sys_init();//系统初始化
    usb_init();//USB CDC 接口配置
    EA = 1;       
       
        LEDON = 0 ;       // 打开P2上的LED开关
       
        while(1)
        {
                if(button_P33 == 0)                                                        // 按键1首次按下,button_P33,button_P34按下为0,松开为1
                {
                        delay_ms(10);
                        if(button_P33 == 0)                                                // 按键消抖,再次确认按键1已按下
                        {
                                while(button_P33 == 0);                                // 按键1按下后需松开才运行下面程序
                                BEEP_on(on_time);                                        // 蜂鸣器响100ms表示开机
                                //开机LED闪烁
                                On_Off_Blinker(on_led_blinker_time,on_led_blinker_times);       
                                while(button_P33 !=0)                                // 按键1已松开,表示已开机,可按P34执行功能选择,再次按下P33则跳出循环
                                {
                                        if(button_P34 == 0)                                // 按键2按下
                                        {                                               
                                                delay_ms(10);
                                                if(button_P34 == 0)                        // 按键消抖,再次确认按键2已按下
                                                {
                                                        while(button_P34 == 0); // 按键2按下后需松开才运行下面程序
                                                        BEEP_on(fu_time);                // 选择功能蜂鸣响时10ms
                                                        P2 = LED;
                                                        a++;
                                                }
                                                if(a>=8) a = 0;                                //当a=8 时,功能选择完毕,对a置0,又重新开始
                                        }
                                }
                                a = 0;                                                                //对a清零,避免下次开机时记忆在P2点灯状态下,又从功能1开始
                                BEEP_on(of_time);                                        // 蜂鸣器长响1000ms表示关机
                                //关机LED闪烁
                                On_Off_Blinker(of_led_blinker_time,of_led_blinker_times);
                                while(button_P33 == 0);                                // 防止一直按着按键1不松,等松开后又开机
                        }
                }
        }
}

void delay_ms(u16 ms)
{
        u16 i;       
        do
        {
                i = MAIN_Fosc/6000;
                while(--i);
        } while(--ms);
}

void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    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 初始化 ======
    P3M0 &= ~0x03;
    P3M1 |= 0x03;
   
    IRC48MCR = 0x80;
    while (!(IRC48MCR & 0x01));
}

void BEEP_on(u16 ms)                //蜂鸣器响铃延时函数
{
        BEEP = 0;
        delay_ms(ms);
        BEEP = 1;
}

void On_Off_Blinker(u16 ms,u8 times)                //开关机亮灯频率与次数
{
        for(times; times>0; times--)
        {
                P2 = LED;
                delay_ms(ms);
                P2 = LED;
                delay_ms(ms);
        }
}


dumon 发表于 2024-3-12 08:40:51

92


程序演示视频如上:

dumon 发表于 2024-3-12 13:41:26

第8集 蜂鸣器实战应用(实操)——冲哥视频思路
1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。
4.增加按键3,按下后表示启动,选择的对应的功能的LED持续闪烁,表示正在工作,
且在工作的时候无法切换功能和关机。关机必须再长按KEY3后,退出运行状态,
才能关机。

动作流程:        先按KEY1开机 → 按KEY2选择工作模式 → 按KEY3启动 → 再按KEY3停止 → 按KEY1关机
说明:
1.未按KEY3启动前,可随时按KEY1进行关机;
2.按KEY3启动后,只能再长按KEY3退出运行,此时不能再选择工作模式,只能再按KEY1关机后,重新开机选择工作模式运行。

用2个位变量(bit Run_Flag,bit RunState)来存储状态,位变量就是只有0或1两个值,如开/关机,启动/停止状态。

冲哥视频的思路是3个if(),每个if去完成不同的功能模块,如第1个if是去完成开/关机——KEY1,第2个if是去选择工作模式——KEY2,第3个if是启动和停止——KEY3。

KEY1来控制Run_Flag的状态转换,初始状态Run_Flag=0,当KEY1按下后,如果是关机状态,执行开机程序,如果是开机状态,执行关机程序。通过对Run_Flag的判断,来执行对应的程序,并则执行程序后把Run_Flag取相反值。
即如果Run_Flag = 0,KEY1按下后,Run_Flag = 1,执行开机程序, 当Run_Flag = 1时,KEY1按下,Run_Flag = 0,执行关机程序。这里就是前面所学的按键点灯,先按下点灯,再按下熄灭,不断循环。

第2个if()主要就是加入了两个与条件,即Run_Flag ==1,RunState == 0,必须同时满足在“开机状态”和“停止状态”,才能按下KEY2键切换不同工作模式。这样才能满足我们第4点要求。
因为有8种模式,所以在内部写了1个循环8次移动LED的程序。

第3个if()主要是说明KEY3按键的功能,KEY3有个执行的前提条件:处于开机状态,并选好工作模式,KEY3按下才起作用,所以这里也是与运算。
这里做了一个很巧妙的地方,当已按KEY1开机,并且按KEY2选择好工作模式,按下KEY3,会进入启动状态,这里有个while()循环,不停闪烁模式代表的LED灯。这里面就必须设定1个跳出循环的条件,即如果在循环中我检测到KEY3再次按下,那么我就将循环的条件改变,就会跳出while()循环,从而达到将运行状态切换到停止状态的目的。

这里要注意的是,如果按KEY3已进入启动状态,那么必须再次长按KEY3退出启动状态,再按KEY1才可以关机,关机程序中会对Run_Flag =0,RunState = 0,RunMode = 0操作,这样才能继续进入下个选择模式和进行启动状态。程序的运行逻辑是这样。
可以实现功能,但应该还有优化空间。
#include <STC32G.H>
#include "comm/stc32_stc8_usb.h"

#define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void sys_init();

void delay_ms(u16 ms);
void BEEP_on(u16 ms);

bit Run_Flag = 0;                                                // 开关机变量0-1,0表示关机,1表示开机
u8Run_Mode = 0;                                                // 工作模式0~8,0:没有模式
u8StoreMode;                                                        // 存储工作模式
bit RunState = 0;                                                // 启动状态,0启动,1停止

sbit KEY1 = P3^3 ;                                                // 按键1
sbit KEY2 = P3^4 ;                                                // 按键2
sbit KEY3 = P3^5 ;                                                // 按键3

sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
sbit LED20 = P2^0 ;                                                // P2.0上的LED
sbit LED21 = P2^1 ;                                                // P2.1上的LED
sbit LED22 = P2^2 ;                                                // P2.2上的LED
sbit LED23 = P2^3 ;                                                // P2.3上的LED
sbit LED24 = P2^4 ;                                                // P2.4上的LED
sbit LED25 = P2^5 ;                                                // P2.5上的LED
sbit LED26 = P2^6 ;                                                // P2.6上的LED
sbit LED27 = P2^7 ;                                                // P2.7上的LED

sbit BEEP = P5^4;                                                // 蜂鸣器

u8 a;                                                                        // LED数组索引号

u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms

void main()
{
        sys_init();//系统初始化
    usb_init();//USB CDC 接口配置
    EA = 1;       
               
        while(1)
        {
                if(KEY1 == 0)
                {
                        delay_ms(10);
                        if(KEY1 == 0)
                        {
                                while(KEY1 == 0);                // 等待KEY1松开后执行下面程序
                                if(Run_Flag == 0)                // 如果是关机状态,执行开机程序
                                {
                                        Run_Flag = 1;
                                        BEEP_on(10);
                                        LEDON = 0 ;                       // 打开P2上的LED开关,这里就设置了必须处于开机状态,KEY2按键才能生效
                                        P2 = 0x00;
                                        delay_ms(200);
                                        P2 = 0xFF;                                       
                                }
                                else                                        // 如果是开机状态,执行关机程序
                                {
                                        Run_Flag = 0;
                                        BEEP_on(10);
                                        LEDON = 1 ;                        // 关闭P2上的LED总开关
                                        P2 = 0xFF;
                                        Run_Mode = 0;
                                        RunState = 0;                // 关机后变为停止状态
                                }
                        }
                }
               
                if(Run_Flag == 1 && RunState == 0 && KEY2 == 0)        // 必须开机后KEY2按键才能切换模式
                {
                        delay_ms(10);
                        if(Run_Flag == 1 && RunState == 0 && KEY2 == 0)
                        {
                                while(KEY2 == 0);                // 等待KEY2松开后执行下面程序
                                BEEP_on(10);
                                ++Run_Mode;
                                if(Run_Mode>8)        Run_Mode = 1;
                                StoreMode = ~(1<<(Run_Mode-1));        // 0000 0001 向右移位
                                P2 = StoreMode ;
                        }
                       
                }
               
                if(Run_Flag == 1 && Run_Mode>0 && KEY3 == 0)        // 处于开机状态,并选好工作模式,KEY3按下才起作用
                {
                        delay_ms(10);                       
                        if(Run_Flag == 1 && RunState == 0 && KEY3 == 0)
                        {

                                while(KEY3 == 0);                // KEY3松开后才执行下面程序
                                while(RunState == 0)        // 循环工作,检测到有KEY3按下则转为停止
                                {
                                        // 保持为当前工作模式
                                        P2 = StoreMode;
                                        delay_ms(200);
                                        P2 = 0xFF;
                                        delay_ms(200);                                       
                                        if(KEY3 == 0)                // KEY3再次按下时,变为停止
                                        {
                                                delay_ms(10);
                                                if(KEY3 == 0)
                                                {
                                                        while(KEY3 == 0);
                                                        RunState = 1;        // 变为停止状态
                                                }
                                        }
                                }
                        }
                }
        }
}

void delay_ms(u16 ms)
{
        u16 i;       
        do
        {
                i = MAIN_Fosc/6000;
                while(--i);
        } while(--ms);
}

void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    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 初始化 ======
    P3M0 &= ~0x03;
    P3M1 |= 0x03;
   
    IRC48MCR = 0x80;
    while (!(IRC48MCR & 0x01));
}

void BEEP_on(u16 ms)
{
        BEEP = 0;
        delay_ms(ms);
        BEEP = 1;
}
93


dumon 发表于 2024-3-13 22:22:49

第8集 蜂鸣器实战应用(实操)——冲哥视频思路


本程序在上一个程序的基础上有做更新,主要是第3个if()程序,根据按键点灯那栏所学,用按键去切换状态,不断按下对状态取反操作,可以达到按一下点灯,再按一下关灯的目的。
本次程序增加功能:KEY2只要在开机状态和KEY2按下时就能选择工作模式,KEY3在开机后第1次按下为启动状态,并进入锁定状态,此时按KEY2和KEY1键均不能起作用,必须再按KEY3到停止状态,此时可以继续按KEY2选择功能或按KEY1直接关机。或者继续按KEY3又继续进入启动状态。
这样是不是很像我们洗衣机,洗衣机的盖子有个感应器,当我们在洗衣机工作时直接打开盖子,是不是洗衣机会立刻停止。那假如我们想往里面再加衣服怎么办,是不是有个启动/暂停键,我们按下这个键就可以打开盖子往里加衣服,并且再次按启动键后又可以继续运行之前的设定过程。本程序就是模拟这个情况。

所以,程序是来源于生活,程序需要贴紧生活,根据实际需求不断去完善我们的程序!
/***********************************************************************
        第8集 蜂鸣器实战应用(实操)——冲哥视频思路
1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。
4.增加按键3,按下后表示启动,选择的对应的功能的LED持续闪烁,表示正在工作,
且在工作的时候无法切换功能和关机。关机必须再长按KEY3后,退出运行状态,
才能关机。

动作流程:        先按KEY1开机 → 按KEY2选择工作模式 → 按KEY3启动 → 再按KEY3停止 → 按KEY1关机
说明:
1.按KEY2选择好工作模式后,按KEY3进入运行模式,再按KEY3退出运行模式,此时再按KEY3会继续运行上次工作模式,
<font color="#ff0000">2.按KEY3退出运行模式后,再按KEY2可再修改工作模式。这里KEY3充当1个暂停键的作用。</font>
3.进行运行模式后,需先按KEY3退出运行模式,再按KEY1关机。
***********************************************************************/

#include <STC32G.H>
#include "comm/stc32_stc8_usb.h"

#define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void sys_init();

void delay_ms(u16 ms);
void BEEP_on(u16 ms);

bit Run_Flag = 0;                                                // 开关机变量0-1,0表示关机,1表示开机
u8Run_Mode = 0;                                                // 工作模式0~8,0:没有模式
u8StoreMode = 0xFE;                                        // 存储工作模式
bit RunState = 0;                                                // 启动状态,0启动,1停止

sbit KEY1 = P3^3 ;                                                // 按键1
sbit KEY2 = P3^4 ;                                                // 按键2
sbit KEY3 = P3^5 ;                                                // 按键3

sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
sbit LED20 = P2^0 ;                                                // P2.0上的LED
sbit LED21 = P2^1 ;                                                // P2.1上的LED
sbit LED22 = P2^2 ;                                                // P2.2上的LED
sbit LED23 = P2^3 ;                                                // P2.3上的LED
sbit LED24 = P2^4 ;                                                // P2.4上的LED
sbit LED25 = P2^5 ;                                                // P2.5上的LED
sbit LED26 = P2^6 ;                                                // P2.6上的LED
sbit LED27 = P2^7 ;                                                // P2.7上的LED

sbit BEEP = P5^4;                                                // 蜂鸣器

u8 a;                                                                        // LED数组索引号

u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms

void main()
{
        sys_init();//系统初始化
    usb_init();//USB CDC 接口配置
    EA = 1;       
               
        while(1)
        {
                if(KEY1 == 0)
                {
                        delay_ms(10);
                        if(KEY1 == 0)
                        {
                                while(KEY1 == 0);                // 等待KEY1松开后执行下面程序
                                if(Run_Flag == 0)                // 如果是关机状态,执行开机程序
                                {
                                        Run_Flag = 1;
                                        BEEP_on(10);
                                        LEDON = 0 ;                       // 打开P2上的LED开关,这里就设置了必须处于开机状态,KEY2按键才能生效
                                        P2 = 0x00;
                                        delay_ms(200);
                                        P2 = 0xFF;                                       
                                }
                                else                                        // 如果是开机状态,执行关机程序
                                {
                                        Run_Flag = 0;
                                        BEEP_on(10);
                                        LEDON = 1 ;                        // 关闭P2上的LED总开关
                                        P2 = 0xFF;
                                        Run_Mode = 0;
                                        RunState = 0;                // 关机后变为停止状态
                                }
                        }
                }
               
                if(Run_Flag == 1 && KEY2 == 0)        // 必须开机后KEY2按键才能切换模式
                {
                        delay_ms(10);
                        if(Run_Flag == 1 && KEY2 == 0)
                        {
                                while(KEY2 == 0);                // 等待KEY2松开后执行下面程序
                                BEEP_on(10);
                                ++Run_Mode;
                                if(Run_Mode>8)        Run_Mode = 1;
                                StoreMode = ~(1<<(Run_Mode-1));        // 0000 0001 向右移位
                                P2 = StoreMode ;
                        }
                       
                }
               
                if(Run_Flag == 1 && Run_Mode>0 && KEY3 == 0)        // 处于开机状态,并选好工作模式,KEY3按下才起作用
                {
                        delay_ms(10);       

                        if(Run_Flag == 1 && RunState == 0 && KEY3 == 0)
                        {
                                RunState = !RunState;        // 变为停止状态
                                while(KEY3 == 0);                // KEY3松开后才执行下面程序
                                while(RunState == 1)        // 循环工作,检测到有KEY3按下则转为停止
                                {
                                        // 保持为当前工作模式
                                        P2 = StoreMode;
                                        delay_ms(200);
                                        P2 = 0xFF;
                                        delay_ms(200);                                       
                                        if(KEY3 == 0)                // KEY3再次按下时,变为停止
                                        {
                                                delay_ms(10);
                                                if(KEY3 == 0)
                                                {
                                                        while(KEY3 == 0);
                                                        RunState = 0;        // 变为停止状态
                                                }
                                        }
                                }
                        }
                }
        }
}

void delay_ms(u16 ms)
{
        u16 i;       
        do
        {
                i = MAIN_Fosc/6000;
                while(--i);
        } while(--ms);
}

void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    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 初始化 ======
    P3M0 &= ~0x03;
    P3M1 |= 0x03;
   
    IRC48MCR = 0x80;
    while (!(IRC48MCR & 0x01));
}

void BEEP_on(u16 ms)
{
        BEEP = 0;
        delay_ms(ms);
        BEEP = 1;
}

dumon 发表于 2024-3-14 15:01:42

第9集数码管的静态显示


1位数码管可以看做是共阴极或共阳极的多个LED的组合,比如我们常见的7段式共阴极数码管,就是7个LED把他们的阴极全部连到GND上,那是不是还剩下7个阳极,当我们分别给这7个LED的阳极接到VCC,是不是我们就可以得到各种组合。那把这7个LED排成8的样子,是不是就可以显示0~9这几个数字了。通过不同的组合还可以形成字母等等。


那如果是多位数码管,那他们内部是怎么连线的呢,其实也很简单。假如现在有4位数码管,这个位就代表共阴或共阳极,4表示这个数码管共有4个共阴或共阳极,这里还有1个概念,叫段码,段码简单理解为单个数码管内LED的数量。加上小数点,我们1位数码管就有8个LED在里面,称之为8段,用A,B,C,D,E,F,G,DP表示,4位数码管的每一段都是连到一起的,比如第1位,第2位,第3位,第4位的A是全部联到一起的。那4位数码管共有几个引脚呢,8个段码+4个位码,共12个。如果我们给第1个位码高电平,第1段低电平,那么第1位上的第1个段码LED会点亮。如果1,2,3,4位全部接高电平,第1段接你电平,那么4个位上的第1段全部会点亮。这就是数码管的引脚说明。段码就是组成1个图案里有多少个LED灯,可能实际里面不只8个,还有米字形的。这个要看自己的个人需要。


                              第1位      第2位   第3位       第4位   ... ...第n位
                               ____       ____       ____       ____            ____
                              | ___ |      | ___ |      | ___ |      | ___ |         | ___ |
                              | ___ | .    | ___ | .    | ___ | .    | ___ | .         | ___ | .


// 数码管相关说明,P0.0~P0.7为数码管的8个段码,P1.0,P1.1,P1.3为3个位码,共阴极数码管
// 位码要接低电平、段码接高电平,共阳极数码管位码要接高电平、段码接低电平,如:给第1位数码管位码低电平,数码管段码‘A’高电平,就能点亮第1位上的‘A'段码,如果给第1,2,3数码管位码低电平,数码管段码‘A’高电平,就能点亮第1,2,3位上的‘A'段码,
sbit DIG_A        = P0^0;                // 数码管段码‘A’
sbit DIG_B        = P0^0;                // 数码管段码‘B’
sbit DIG_C        = P0^0;                // 数码管段码‘C’
sbit DIG_D        = P0^0;                // 数码管段码‘D’
sbit DIG_E        = P0^0;                // 数码管段码‘E’
sbit DIG_F        = P0^0;                // 数码管段码‘F’
sbit DIG_G        = P0^0;                // 数码管段码‘G’
sbit DIG_P        = P0^0;                // 数码管段码‘dP’


sbit SEG_1        = P1^0;                // 第1位数码管位码
sbit SEG_2        = P1^1;                // 第2位数码管位码
sbit SEG_3        = P1^3;                // 第3位数码管位码



/*
               P0.7             P0.6              P0.5              P0.4             P0.3             P0.2             P0.1              P0.0                   BIN                HEX
不带小数    DP                G                F                E                D                C                B                A                       
        '0'      0                0                1                1                1                1                1                1                0011 1111             0x3F
        '1'      0                0                0                0                0                1                1                0                0000 0110             0x06
        '2'      0                1                0                1                1                0                1                1                0101 1011             0x5B
        '3'      0                1                0                0                1                1                1                1                0100 1111             0x4F
        '4'      0                1                1                0                0                1                1                0                0110 0110             0x66
        '5'      0                1                1                0                1                1                0                1                0110 1101      0x6D
        '6'      0                1                1                1                1                1                0                1                0111 1101      0x7D
        '7'      0                0                0                0                0                1                1                1                0000 0111      0x07
        '8'      0                1                1                1                1                1                1                1                0111 1111             0x7F
        '9'   0                1                1                0                1                1                1                1                0110 1111             0x6F

带小数点就把P0.7全部置1,再重新计算8位二进制数的HEX值                               
*/

把段码和位码编入数组,就可以让数码管显示任何你想要的图形了。

u8 DIG_Number = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,        /*不带小数点*/
                                       0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF, /*带小数点*/
                                       0x00 /*全部熄灭*/};

u8 SEG_Number= {0xFE,0xFD,0xF7};


用1个循环嵌套就能实现在从第1位显示到第n位,段码也可以循环显示

                while(a<3)
                {                       
                        P1 = SEG_Number;            // 先选择位码
                        while(b<21)
                        {                               
                                P0 = DIG_Number;      // 再选择段码
                                delay_ms(100);
                                b++;                              //段码数组循环
                        }
                        b = 0;                                    // 对b值复位
                        a++;                                     // 跳到下个位码
                }
                a = 0;                                           //到达第3个位码后复位



本集最后留了1个问题,通过上面的实例,我们已经实现了数码管显示字符,但是有没有发现,是不是4个位或多个位都只能显示相同的段码内容,如果想在每个位码上显示不同的数字或字符,就需要学习下一课的内容了,数码管的动态显示,让数码管的每个位显示不同数字,如1234。


电子爱好者2024 发表于 2024-3-14 20:50:14

非常好的版主,适合小白来学习,以后就跟着您来混啦!{:5_300:}

dumon 发表于 2024-3-15 08:44:31

自己作为一个也刚开始接触学习STC单片机的学习者,学无先后,希望自己在课程中发现的和遇到的一些问题能够分享给大家,让大家少走一些弯路,多避一些坑,就感到非常满足了。
分享也是一种快乐!并乐在其中!感谢大家的支持与鼓励!{:handshake:}

soma 发表于 2024-3-15 09:23:42

能自己搭硬件的都是牛人啊
页: 1 [2] 3 4 5
查看完整版本: 跟 冲哥教学视频学习STC——记录每一天的成长| 必须立即送强大的实验箱支持啊 !