找回密码
 立即注册
楼主: du***

跟 冲哥教学视频学习STC——记录每一天的成长| 必须立即送强大的实验箱支持啊 !

[复制链接]
  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 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上电后上拉或下拉就能知道了,这也是一个非常重要的知识点。

    上拉电阻与下拉电阻 说明.png
    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 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也是一个经典的案例,单按钮启停。从这里也能找到对照哦。

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


    1. /***********************************************************************
    2.         第7集 按键点灯(实操)
    3. 1.P3.3按键按下P2.0上的LED点亮,松开熄灭
    4. 2.P3.4按键按下P2.7上的LED熄灭,松开点亮
    5. 3.P3.5按键按下一次,P2.1上的LED状态改变一次
    6. 4.P3.3按键按下一次,LED往左边走一个,P3.5按键按下一次,LED往右边走一个,
    7. ***********************************************************************/
    8. #include <STC32G.H>
    9. #include "comm/stc32_stc8_usb.h"
    10. #define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz
    11. char *USER_DEVICEDESC = NULL;
    12. char *USER_PRODUCTDESC = NULL;
    13. char *USER_STCISPCMD = "@STCISP#";
    14. void sys_init();
    15. void delay_ms(u16 ms);
    16. sbit button_P33 = P3^3 ;                                // 按键P3.3,上拉到5V
    17. sbit button_P34 = P3^4 ;                                // 按键P3.4,上拉到5V
    18. sbit button_P35 = P3^5 ;                                // 按键P3.4,上拉到5V
    19. sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
    20. sbit LED20 = P2^0 ;                                                // P2.0上的LED
    21. sbit LED21 = P2^1 ;                                                // P2.1上的LED
    22. sbit LED27 = P2^7 ;                                                // P2.7上的LED
    23. bit buttonState ;                                                // 布尔变量存储按键状态
    24. void main()
    25. {
    26.         sys_init();  //系统初始化
    27.     usb_init();  //USB CDC 接口配置
    28.     EA = 1;       
    29.        
    30.         LEDON = 0 ;
    31.         P2 = 0xFE ;
    32.        
    33.         while(1)
    34.         {
    35. // 1.P3.3按键按下P2.0上的LED点亮,松开熄灭               
    36.                 if(button_P33 == 0)
    37.                 {
    38.                         delay_ms(10);
    39.                         while(button_P33 == 0)
    40.                         {
    41.                                 LED20 = 0 ;
    42.                         }
    43.                         LED20 = 1;
    44.                 }
    45.                
    46. // 2.P3.4按键按下P2.7上的LED熄灭,松开点亮
    47.                 if(button_P34 == 0)
    48.                 {
    49.                         delay_ms(10);
    50.                         while(button_P34 == 0)
    51.                         {
    52.                                 LED27 = 1 ;
    53.                         }
    54.                         LED27 = 0;
    55.                 }
    56. // 3.1 P3.5按键按下一次,P2.1上的LED状态改变一次
    57.                 if(button_P35 == 0)
    58.                 {
    59.                         delay_ms(10);
    60.                         if(button_P35 == 0)
    61.                         {
    62.                                 while(button_P35 == 0)
    63.                                 {
    64.                                         LED21 = buttonState ;
    65.                                 }
    66.                                 buttonState = !buttonState ;
    67.                         }
    68.                 }
    69.                
    70. // 3.2 P3.5按键按下一次,P2.1上的LED状态改变一次,按下后立刻执行
    71. //                if(button_P35 == 0)
    72. //                {
    73. //                        delay_ms(10);
    74. //                        if(button_P35 == 0)
    75. //                        {
    76. //                                LED21 = !LED21 ;
    77. //                                while(button_P35 == 0);
    78. //                        }
    79. //                }
    80. // 3.3 P3.5按键按下一次,P2.1上的LED状态改变一次,教材中冲哥的方法,松开按键后执行,滞后性
    81. //                if(button_P35 == 0)
    82. //                {
    83. //                        delay_ms(10);
    84. //                        if(button_P35 == 0)
    85. //                        {
    86. //                                while(button_P35 == 0);                               
    87. //                                LED21 = !LED21 ;
    88. //                        }
    89. //                }               
    90. // 4.P3.3按键按下一次,LED往左边走一个,P3.5按键按下一次,LED往右边走一个,
    91. //                if(button_P33 == 0)
    92. //                {
    93. //                        delay_ms(10);
    94. //                        if(button_P33 == 0)
    95. //                        {
    96. //                                P2 = (P2<<1)+1;                                // LED往左移动1个
    97. //                                while(button_P33 == 0);                // 检测到按键未释放时,停留在此步
    98. //                                if(P2 == 0xFF)                                // 当最左边LED点亮时,切换到最右边LED
    99. //                                {
    100. //                                        P2 = 0xFE;
    101. //                                }
    102. //                        }
    103. //                }
    104. //                if(button_P35 == 0)
    105. //                {
    106. //                        delay_ms(10);
    107. //                        if(button_P35 == 0)
    108. //                        {
    109. //                                P2 = (P2>>1)|0x80;                        // LED往右移动1个
    110. //                                while(button_P35 == 0);                // 检测到按键未释放时,停留在此步
    111. //                                if(P2 == 0xFF)                                // 当最右边LED点亮时,切换到最左边LED
    112. //                                {
    113. //                                        P2 = 0x7F;
    114. //                                }
    115. //                        }
    116. //                }
    117.         }
    118. }
    119. void delay_ms(u16 ms)
    120. {
    121.         u16 i;       
    122.         do
    123.         {
    124.                 i = MAIN_Fosc/6000;
    125.                 while(--i);
    126.         } while(--ms);
    127. }
    128. void sys_init()
    129. {
    130.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    131.     EAXFR = 1; //扩展寄存器(XFR)访问使能
    132.     CKCON = 0; //提高访问XRAM速度
    133.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    134.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    135.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    136.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    137.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    138.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    139.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    140.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    141.     //====== USB 初始化 ======
    142.     P3M0 &= ~0x03;
    143.     P3M1 |= 0x03;
    144.    
    145.     IRC48MCR = 0x80;
    146.     while (!(IRC48MCR & 0x01));
    147. }
    复制代码




    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 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我按下一直不松,会不会一直循环开机关机之类。

    这里我用的是跟冲哥不一样的思路,我在学习的时候我都会先不看冲哥的编程,而是自己先思考一遍,自己根据前面所学我是否能独立的把这个程序编辑出来,如果想不通再去参考下冲哥和程序思路,这样可以做到举一反三,拓展自己的处理问题的方式。

    下面请看我自己所编写的程序,经过实测可以达到程序要求的功能。具体介绍都在程序注释内,希望能给朋友们一些启发。
    开发板放在公司里了,没有及时用相机拍下程序运行的画面,待周一补上吧。


    1. /***********************************************************************
    2.         第8集 蜂鸣器实战应用(实操)
    3. 1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
    4. 2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
    5. 3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。
    6. ***********************************************************************/
    7. #include <STC32G.H>
    8. #include "comm/stc32_stc8_usb.h"
    9. #define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz
    10. char *USER_DEVICEDESC = NULL;
    11. char *USER_PRODUCTDESC = NULL;
    12. char *USER_STCISPCMD = "@STCISP#";
    13. void sys_init();
    14. void delay_ms(u16 ms);
    15. void BEEP_on(u16 ms);
    16. void On_Off_Blinker(u16 ms,u8 times);
    17. sbit button_P33 = P3^3 ;                                // 按键1 上电后是上拉到5V,开关按下是下拉到0V
    18. sbit button_P34 = P3^4 ;                                // 按键2 上电后是上拉到5V,开关按下是下拉到0V
    19. sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
    20. sbit LED20 = P2^0 ;                                                // P2.0上的LED
    21. sbit LED21 = P2^1 ;                                                // P2.1上的LED
    22. sbit LED22 = P2^2 ;                                                // P2.2上的LED
    23. sbit LED23 = P2^3 ;                                                // P2.3上的LED
    24. sbit LED24 = P2^4 ;                                                // P2.4上的LED
    25. sbit LED25 = P2^5 ;                                                // P2.5上的LED
    26. sbit LED26 = P2^6 ;                                                // P2.6上的LED
    27. sbit LED27 = P2^7 ;                                                // P2.7上的LED
    28. sbit BEEP = P5^4;                                                // 蜂鸣器
    29. bit buttonState ;                                                // 布尔变量存储按键状态
    30. u8 a;                                                                        // LED数组索引号
    31. u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
    32. u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
    33. u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms
    34. u16 on_led_blinker_time = 200;                        // 开机LED点亮时间200ms
    35. u16 of_led_blinker_time = 500;                        // 关机LED点亮时间500ms
    36. u8  on_led_blinker_times = 1;                        // 开机LED闪烁次数1次
    37. u8  of_led_blinker_times = 3;                        // 关机LED闪烁次数3次
    38. u8 LED[10] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,0x00,0xFF };                                                // 数组用于记录8个LED灯
    39. // 1111 1110 0xFE;
    40. // 1111 1101 0xFD;
    41. // 1111 1011 0xFB;
    42. // 1111 0111 0xF7;
    43. // 1110 1111 0xEF;
    44. // 1101 1111 0xDF;
    45. // 1011 1111 0xBF;
    46. // 0111 1111 0x7F;
    47. void main()
    48. {
    49.         sys_init();  //系统初始化
    50.     usb_init();  //USB CDC 接口配置
    51.     EA = 1;       
    52.        
    53.         LEDON = 0 ;         // 打开P2上的LED开关
    54.        
    55.         while(1)
    56.         {
    57.                 if(button_P33 == 0)                                                        // 按键1首次按下,button_P33,button_P34按下为0,松开为1
    58.                 {
    59.                         delay_ms(10);
    60.                         if(button_P33 == 0)                                                // 按键消抖,再次确认按键1已按下
    61.                         {
    62.                                 while(button_P33 == 0);                                // 按键1按下后需松开才运行下面程序
    63.                                 BEEP_on(on_time);                                        // 蜂鸣器响100ms表示开机
    64.                                 //开机LED闪烁
    65.                                 On_Off_Blinker(on_led_blinker_time,on_led_blinker_times);       
    66.                                 while(button_P33 !=0)                                // 按键1已松开,表示已开机,可按P34执行功能选择,再次按下P33则跳出循环
    67.                                 {
    68.                                         if(button_P34 == 0)                                // 按键2按下
    69.                                         {                                               
    70.                                                 delay_ms(10);
    71.                                                 if(button_P34 == 0)                        // 按键消抖,再次确认按键2已按下
    72.                                                 {
    73.                                                         while(button_P34 == 0); // 按键2按下后需松开才运行下面程序
    74.                                                         BEEP_on(fu_time);                // 选择功能蜂鸣响时10ms
    75.                                                         P2 = LED[a];
    76.                                                         a++;
    77.                                                 }
    78.                                                 if(a>=8) a = 0;                                //当a=8 时,功能选择完毕,对a置0,又重新开始
    79.                                         }
    80.                                 }
    81.                                 a = 0;                                                                //对a清零,避免下次开机时记忆在P2点灯状态下,又从功能1开始
    82.                                 BEEP_on(of_time);                                        // 蜂鸣器长响1000ms表示关机
    83.                                 //关机LED闪烁
    84.                                 On_Off_Blinker(of_led_blinker_time,of_led_blinker_times);
    85.                                 while(button_P33 == 0);                                // 防止一直按着按键1不松,等松开后又开机
    86.                         }
    87.                 }
    88.         }
    89. }
    90. void delay_ms(u16 ms)
    91. {
    92.         u16 i;       
    93.         do
    94.         {
    95.                 i = MAIN_Fosc/6000;
    96.                 while(--i);
    97.         } while(--ms);
    98. }
    99. void sys_init()
    100. {
    101.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    102.     EAXFR = 1; //扩展寄存器(XFR)访问使能
    103.     CKCON = 0; //提高访问XRAM速度
    104.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    105.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    106.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    107.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    108.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    109.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    110.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    111.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    112.     //====== USB 初始化 ======
    113.     P3M0 &= ~0x03;
    114.     P3M1 |= 0x03;
    115.    
    116.     IRC48MCR = 0x80;
    117.     while (!(IRC48MCR & 0x01));
    118. }
    119. void BEEP_on(u16 ms)                //蜂鸣器响铃延时函数
    120. {
    121.         BEEP = 0;
    122.         delay_ms(ms);
    123.         BEEP = 1;
    124. }
    125. void On_Off_Blinker(u16 ms,u8 times)                //开关机亮灯频率与次数
    126. {
    127.         for(times; times>0; times--)
    128.         {
    129.                 P2 = LED[8];
    130.                 delay_ms(ms);
    131.                 P2 = LED[9];
    132.                 delay_ms(ms);
    133.         }
    134. }
    复制代码



    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 2024-3-12 08:40:51 | 显示全部楼层



    程序演示视频如上:
    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 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操作,这样才能继续进入下个选择模式和进行启动状态。程序的运行逻辑是这样。
    可以实现功能,但应该还有优化空间。
    1. #include <STC32G.H>
    2. #include "comm/stc32_stc8_usb.h"
    3. #define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz
    4. char *USER_DEVICEDESC = NULL;
    5. char *USER_PRODUCTDESC = NULL;
    6. char *USER_STCISPCMD = "@STCISP#";
    7. void sys_init();
    8. void delay_ms(u16 ms);
    9. void BEEP_on(u16 ms);
    10. bit Run_Flag = 0;                                                // 开关机变量0-1,0表示关机,1表示开机
    11. u8  Run_Mode = 0;                                                // 工作模式0~8,0:没有模式
    12. u8  StoreMode;                                                        // 存储工作模式
    13. bit RunState = 0;                                                // 启动状态,0启动,1停止
    14. sbit KEY1 = P3^3 ;                                                // 按键1
    15. sbit KEY2 = P3^4 ;                                                // 按键2
    16. sbit KEY3 = P3^5 ;                                                // 按键3
    17. sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
    18. sbit LED20 = P2^0 ;                                                // P2.0上的LED
    19. sbit LED21 = P2^1 ;                                                // P2.1上的LED
    20. sbit LED22 = P2^2 ;                                                // P2.2上的LED
    21. sbit LED23 = P2^3 ;                                                // P2.3上的LED
    22. sbit LED24 = P2^4 ;                                                // P2.4上的LED
    23. sbit LED25 = P2^5 ;                                                // P2.5上的LED
    24. sbit LED26 = P2^6 ;                                                // P2.6上的LED
    25. sbit LED27 = P2^7 ;                                                // P2.7上的LED
    26. sbit BEEP = P5^4;                                                // 蜂鸣器
    27. u8 a;                                                                        // LED数组索引号
    28. u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
    29. u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
    30. u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms
    31. void main()
    32. {
    33.         sys_init();  //系统初始化
    34.     usb_init();  //USB CDC 接口配置
    35.     EA = 1;       
    36.                
    37.         while(1)
    38.         {
    39.                 if(KEY1 == 0)
    40.                 {
    41.                         delay_ms(10);
    42.                         if(KEY1 == 0)
    43.                         {
    44.                                 while(KEY1 == 0);                // 等待KEY1松开后执行下面程序
    45.                                 if(Run_Flag == 0)                // 如果是关机状态,执行开机程序
    46.                                 {
    47.                                         Run_Flag = 1;
    48.                                         BEEP_on(10);
    49.                                         LEDON = 0 ;                         // 打开P2上的LED开关,这里就设置了必须处于开机状态,KEY2按键才能生效
    50.                                         P2 = 0x00;
    51.                                         delay_ms(200);
    52.                                         P2 = 0xFF;                                       
    53.                                 }
    54.                                 else                                        // 如果是开机状态,执行关机程序
    55.                                 {
    56.                                         Run_Flag = 0;
    57.                                         BEEP_on(10);
    58.                                         LEDON = 1 ;                        // 关闭P2上的LED总开关
    59.                                         P2 = 0xFF;
    60.                                         Run_Mode = 0;
    61.                                         RunState = 0;                // 关机后变为停止状态
    62.                                 }
    63.                         }
    64.                 }
    65.                
    66.                 if(Run_Flag == 1 && RunState == 0 && KEY2 == 0)        // 必须开机后KEY2按键才能切换模式
    67.                 {
    68.                         delay_ms(10);
    69.                         if(Run_Flag == 1 && RunState == 0 && KEY2 == 0)
    70.                         {
    71.                                 while(KEY2 == 0);                // 等待KEY2松开后执行下面程序
    72.                                 BEEP_on(10);
    73.                                 ++Run_Mode;
    74.                                 if(Run_Mode>8)        Run_Mode = 1;
    75.                                 StoreMode = ~(1<<(Run_Mode-1));        // 0000 0001 向右移位
    76.                                 P2 = StoreMode ;
    77.                         }
    78.                        
    79.                 }
    80.                
    81.                 if(Run_Flag == 1 && Run_Mode>0 && KEY3 == 0)        // 处于开机状态,并选好工作模式,KEY3按下才起作用
    82.                 {
    83.                         delay_ms(10);                       
    84.                         if(Run_Flag == 1 && RunState == 0 && KEY3 == 0)
    85.                         {
    86.                                 while(KEY3 == 0);                // KEY3松开后才执行下面程序
    87.                                 while(RunState == 0)        // 循环工作,检测到有KEY3按下则转为停止
    88.                                 {
    89.                                         // 保持为当前工作模式
    90.                                         P2 = StoreMode;
    91.                                         delay_ms(200);
    92.                                         P2 = 0xFF;
    93.                                         delay_ms(200);                                       
    94.                                         if(KEY3 == 0)                // KEY3再次按下时,变为停止
    95.                                         {
    96.                                                 delay_ms(10);
    97.                                                 if(KEY3 == 0)
    98.                                                 {
    99.                                                         while(KEY3 == 0);
    100.                                                         RunState = 1;        // 变为停止状态
    101.                                                 }
    102.                                         }
    103.                                 }
    104.                         }
    105.                 }
    106.         }
    107. }
    108. void delay_ms(u16 ms)
    109. {
    110.         u16 i;       
    111.         do
    112.         {
    113.                 i = MAIN_Fosc/6000;
    114.                 while(--i);
    115.         } while(--ms);
    116. }
    117. void sys_init()
    118. {
    119.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    120.     EAXFR = 1; //扩展寄存器(XFR)访问使能
    121.     CKCON = 0; //提高访问XRAM速度
    122.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    123.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    124.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    125.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    126.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    127.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    128.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    129.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    130.     //====== USB 初始化 ======
    131.     P3M0 &= ~0x03;
    132.     P3M1 |= 0x03;
    133.    
    134.     IRC48MCR = 0x80;
    135.     while (!(IRC48MCR & 0x01));
    136. }
    137. void BEEP_on(u16 ms)
    138. {
    139.         BEEP = 0;
    140.         delay_ms(ms);
    141.         BEEP = 1;
    142. }
    复制代码




    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 2024-3-13 22:22:49 | 显示全部楼层
    第8集 蜂鸣器实战应用(实操)——冲哥视频思路


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

    所以,程序是来源于生活,程序需要贴紧生活,根据实际需求不断去完善我们的程序!
    1. /***********************************************************************
    2.         第8集 蜂鸣器实战应用(实操)——冲哥视频思路
    3. 1.按键1按下,蜂鸣10ms,LED1~8全部点亮200ms再熄灭,表示开机。
    4. 2.开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
    5. 3.开机后按键1再次按下,蜂鸣10ms,LED全部熄灭,表示关机。
    6. 4.增加按键3,按下后表示启动,选择的对应的功能的LED持续闪烁,表示正在工作,
    7. 且在工作的时候无法切换功能和关机。关机必须再长按KEY3后,退出运行状态,
    8. 才能关机。
    9. 动作流程:        先按KEY1开机 → 按KEY2选择工作模式 → 按KEY3启动 → 再按KEY3停止 → 按KEY1关机
    10. 说明:
    11. 1.按KEY2选择好工作模式后,按KEY3进入运行模式,再按KEY3退出运行模式,此时再按KEY3会继续运行上次工作模式,
    12. <font color="#ff0000">2.按KEY3退出运行模式后,再按KEY2可再修改工作模式。这里KEY3充当1个暂停键的作用。</font>
    13. 3.进行运行模式后,需先按KEY3退出运行模式,再按KEY1关机。
    14. ***********************************************************************/
    15. #include <STC32G.H>
    16. #include "comm/stc32_stc8_usb.h"
    17. #define MAIN_Fosc 24000000UL                        // 定义一个主时钟24MHz
    18. char *USER_DEVICEDESC = NULL;
    19. char *USER_PRODUCTDESC = NULL;
    20. char *USER_STCISPCMD = "@STCISP#";
    21. void sys_init();
    22. void delay_ms(u16 ms);
    23. void BEEP_on(u16 ms);
    24. bit Run_Flag = 0;                                                // 开关机变量0-1,0表示关机,1表示开机
    25. u8  Run_Mode = 0;                                                // 工作模式0~8,0:没有模式
    26. u8  StoreMode = 0xFE;                                        // 存储工作模式
    27. bit RunState = 0;                                                // 启动状态,0启动,1停止
    28. sbit KEY1 = P3^3 ;                                                // 按键1
    29. sbit KEY2 = P3^4 ;                                                // 按键2
    30. sbit KEY3 = P3^5 ;                                                // 按键3
    31. sbit LEDON = P4^5 ;                                                // P4^5 = 0, P2.0~P2.7上的LED才能点亮
    32. sbit LED20 = P2^0 ;                                                // P2.0上的LED
    33. sbit LED21 = P2^1 ;                                                // P2.1上的LED
    34. sbit LED22 = P2^2 ;                                                // P2.2上的LED
    35. sbit LED23 = P2^3 ;                                                // P2.3上的LED
    36. sbit LED24 = P2^4 ;                                                // P2.4上的LED
    37. sbit LED25 = P2^5 ;                                                // P2.5上的LED
    38. sbit LED26 = P2^6 ;                                                // P2.6上的LED
    39. sbit LED27 = P2^7 ;                                                // P2.7上的LED
    40. sbit BEEP = P5^4;                                                // 蜂鸣器
    41. u8 a;                                                                        // LED数组索引号
    42. u16 on_time = 100;                                                // 开机蜂鸣器响时100ms
    43. u16 fu_time = 10;                                                // 选择功能蜂鸣器响时10ms
    44. u16 of_time = 1000;                                                // 关机蜂鸣器响时1000ms
    45. void main()
    46. {
    47.         sys_init();  //系统初始化
    48.     usb_init();  //USB CDC 接口配置
    49.     EA = 1;       
    50.                
    51.         while(1)
    52.         {
    53.                 if(KEY1 == 0)
    54.                 {
    55.                         delay_ms(10);
    56.                         if(KEY1 == 0)
    57.                         {
    58.                                 while(KEY1 == 0);                // 等待KEY1松开后执行下面程序
    59.                                 if(Run_Flag == 0)                // 如果是关机状态,执行开机程序
    60.                                 {
    61.                                         Run_Flag = 1;
    62.                                         BEEP_on(10);
    63.                                         LEDON = 0 ;                         // 打开P2上的LED开关,这里就设置了必须处于开机状态,KEY2按键才能生效
    64.                                         P2 = 0x00;
    65.                                         delay_ms(200);
    66.                                         P2 = 0xFF;                                       
    67.                                 }
    68.                                 else                                        // 如果是开机状态,执行关机程序
    69.                                 {
    70.                                         Run_Flag = 0;
    71.                                         BEEP_on(10);
    72.                                         LEDON = 1 ;                        // 关闭P2上的LED总开关
    73.                                         P2 = 0xFF;
    74.                                         Run_Mode = 0;
    75.                                         RunState = 0;                // 关机后变为停止状态
    76.                                 }
    77.                         }
    78.                 }
    79.                
    80.                 if(Run_Flag == 1 && KEY2 == 0)        // 必须开机后KEY2按键才能切换模式
    81.                 {
    82.                         delay_ms(10);
    83.                         if(Run_Flag == 1 && KEY2 == 0)
    84.                         {
    85.                                 while(KEY2 == 0);                // 等待KEY2松开后执行下面程序
    86.                                 BEEP_on(10);
    87.                                 ++Run_Mode;
    88.                                 if(Run_Mode>8)        Run_Mode = 1;
    89.                                 StoreMode = ~(1<<(Run_Mode-1));        // 0000 0001 向右移位
    90.                                 P2 = StoreMode ;
    91.                         }
    92.                        
    93.                 }
    94.                
    95.                 if(Run_Flag == 1 && Run_Mode>0 && KEY3 == 0)        // 处于开机状态,并选好工作模式,KEY3按下才起作用
    96.                 {
    97.                         delay_ms(10);       
    98.                         if(Run_Flag == 1 && RunState == 0 && KEY3 == 0)
    99.                         {
    100.                                 RunState = !RunState;        // 变为停止状态
    101.                                 while(KEY3 == 0);                // KEY3松开后才执行下面程序
    102.                                 while(RunState == 1)        // 循环工作,检测到有KEY3按下则转为停止
    103.                                 {
    104.                                         // 保持为当前工作模式
    105.                                         P2 = StoreMode;
    106.                                         delay_ms(200);
    107.                                         P2 = 0xFF;
    108.                                         delay_ms(200);                                       
    109.                                         if(KEY3 == 0)                // KEY3再次按下时,变为停止
    110.                                         {
    111.                                                 delay_ms(10);
    112.                                                 if(KEY3 == 0)
    113.                                                 {
    114.                                                         while(KEY3 == 0);
    115.                                                         RunState = 0;        // 变为停止状态
    116.                                                 }
    117.                                         }
    118.                                 }
    119.                         }
    120.                 }
    121.         }
    122. }
    123. void delay_ms(u16 ms)
    124. {
    125.         u16 i;       
    126.         do
    127.         {
    128.                 i = MAIN_Fosc/6000;
    129.                 while(--i);
    130.         } while(--ms);
    131. }
    132. void sys_init()
    133. {
    134.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    135.     EAXFR = 1; //扩展寄存器(XFR)访问使能
    136.     CKCON = 0; //提高访问XRAM速度
    137.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    138.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    139.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    140.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    141.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    142.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    143.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    144.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    145.     //====== USB 初始化 ======
    146.     P3M0 &= ~0x03;
    147.     P3M1 |= 0x03;
    148.    
    149.     IRC48MCR = 0x80;
    150.     while (!(IRC48MCR & 0x01));
    151. }
    152. void BEEP_on(u16 ms)
    153. {
    154.         BEEP = 0;
    155.         delay_ms(ms);
    156.         BEEP = 1;
    157. }
    复制代码


    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 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[21] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,        /*不带小数点*/
                                             0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF, /*带小数点*/
                                             0x00 /*全部熄灭*/};

    u8 SEG_Number[3]  = {0xFE,0xFD,0xF7};


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

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



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


    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 06:07
  • 签到天数: 93 天

    [LV.6]常住居民II

    11

    主题

    139

    回帖

    259

    积分

    中级会员

    积分
    259
    发表于 2024-3-14 20:50:14 | 显示全部楼层
    非常好的版主,适合小白来学习,以后就跟着您来混啦!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    昨天 08:45
  • 签到天数: 151 天

    [LV.7]常住居民III

    6

    主题

    66

    回帖

    502

    积分

    高级会员

    积分
    502
     楼主| 发表于 2024-3-15 08:44:31 | 显示全部楼层
    自己作为一个也刚开始接触学习STC单片机的学习者,学无先后,希望自己在课程中发现的和遇到的一些问题能够分享给大家,让大家少走一些弯路,多避一些坑,就感到非常满足了。
    分享也是一种快乐!并乐在其中!感谢大家的支持与鼓励!
    永远相信美好的事情即将发生!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 07:53
  • 签到天数: 101 天

    [LV.6]常住居民II

    9

    主题

    1042

    回帖

    1920

    积分

    金牌会员

    积分
    1920
    发表于 2024-3-15 09:23:42 | 显示全部楼层
    能自己搭硬件的都是牛人啊
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-6-15 00:50 , Processed in 0.668346 second(s), 69 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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