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

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

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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
永远相信美好的事情即将发生!
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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. }
复制代码




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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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. }
复制代码



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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

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



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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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. }
复制代码




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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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. }
复制代码


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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

积分
1666
发表于 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。


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

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:398
  • 最近打卡:2025-05-07 06:15:15
已绑定手机

17

主题

137

回帖

1543

积分

金牌会员

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:448
  • 最近打卡:2025-05-06 10:56:26

9

主题

85

回帖

1666

积分

金牌会员

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:429
  • 最近打卡:2025-05-08 00:01:49
已绑定手机

19

主题

3196

回帖

4956

积分

论坛元老

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

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-8 02:35 , Processed in 1.068034 second(s), 108 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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