chun1234 发表于 2024-7-26 07:59:11

本帖最后由 chun1234 于 2024-7-26 08:06 编辑

学习冲哥的《STC32G单片机视频教程》       第九课   数码管的静态使用


一、认识数码管:      按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管,尾缀A表示共阳,K表示共阴。 二、控制原理:      STC32G开发板使用的是共阳型四位数码管。若以一位的7段数码管为例,一位的数码管加上小数点一共是8个需要控制的发光管,分别是a、b、c、d、e、f、g、dp,由8个引脚分别控制他们的亮灭,也就是说一个引脚控制一个发光管,那么这就是段选。发光的二极管是有两端的,那么这8个发光的二极管有一个公共端,这样就可以控制一位数码管整体,这就是段选。
       由一位数码管延伸到四位数码管时,如图所示,每一个发光管都有相应的引脚控制,每一位的数码管都有自己的公共端,通过公共端来控制哪一位的数码管亮或者是灭,这就是位选。
         
      单片机的P6.0~P6.6引脚分别接到数码管的a~g引脚,就可以通过控制P6各引脚电平的高低来控制数码管七段LED的亮灭;单片机的P7.0~P7.7分别通过8支PNP型三极管,驱动8个数码管的公共端com0~com7,也就是位选端,来控制8位数码管的亮灭。
三、数码管实现0-9的显示          1.用数组定义0-9的内码         2.尝试用延时实现0-9的循环显示         3.用按键控制数字的加或者减。
#include "COMM/stc.h"                        //调用头文件#include "COMM/usb.h" #define KEY1 P32                               //定义一个按键 引脚选择P32#define KEY2 P33                               //定义一个按键 引脚选择P33 #define BEEP P54                               //定义一个按键 引脚选择P54 #define MAIN_Fosc 24000000UL          //定义主时钟 char *USER_DEVICEDESC = NULL;char *USER_PRODUCTDESC = NULL;char *USER_STCISPCMD = "@STCISP#";      u8 SEG_Tab = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 };      //0-9 /*数组内16进制与2进制与实际显示数字对照:0xc01100 0000 ---> 00xf91111 1001 ---> 10xa41010 0100 ---> 20xb01011 0000 ---> 30x991001 1001 ---> 40x921001 0010 ---> 50x821000 0010 ---> 60xf81111 1000 ---> 70x801000 0000 ---> 80x901001 0000 ---> 9*/void sys_init();                                 //函数声明void delay_ms(u16 ms);                  //unsigned int void main()                                    //程序开始运行的入口{      u8 num = 0;      sys_init();                                 //USB功能+IO口初始化      usb_init();                              //usb库初始化      EA = 1;                                    //CPU开放中断,打开总中断。            while(1)                                 //死循环      {                if( DeviceState != DEVSTATE_CONFIGURED )                                 continue;                if( bUsbOutReady )                                                                                {                        usb_OUT_done();                 }                P70 = 0;                        //开启数码管 //------P32按下一次,数码管显示数字加1;P33按下一次,数码管数字减1      -----                                      P6 = SEG_Tab;         //这个数码管输出段码                 if( KEY1 ==0 )                {                        delay_ms(10);                        if( KEY1 ==0 )                        {                              BEEP = 0;                              delay_ms(10);                              BEEP = 1;                              while( KEY1 ==0 );                              if( num<9 )                              {                                        num++;                              }                        }                }                if( KEY2 ==0 )                {                        delay_ms(10);                        if( KEY2 ==0 )                        {                              BEEP = 0;                              delay_ms(10);                              BEEP = 1;                                                            while( KEY2 ==0 );                              if( num>0 )                                        num--;                        }                }                                      }} 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;    //设置为准双向口          P3M0 = 0x00;    P3M1 = 0x00;        P3M0 &= ~0x03;    P3M1 |= 0x03;     //设置USB使用的时钟源    IRC48MCR = 0x80;                  //使能内部48M高速IRC    while (!(IRC48MCR & 0x01));      //等待时钟稳定     USBCLK = 0x00;                        //使用CDC功能需要使用这两行,HID功能禁用这两行。    USBCON = 0x90;} void delay_ms(u16 ms)                  //unsigned int {      u16 i;      do      {                i = MAIN_Fosc/6000;                while(--i);      }while(--ms);}




chun1234 发表于 2024-7-28 08:30:04

本帖最后由 chun1234 于 2024-7-28 08:33 编辑

学习冲哥的《STC32G单片机视频教程》    第十课数码管的动态显示

一、数码管动态刷新的原理:

      动态显示是将所有数码管的8个显示笔划a,b,c,d,e,f,g,dp 的同名端连在一起 ,另外为每个数码管的公共极COM端加位选通控制电路 ,位选通由各自独立的 I/O线控制 ,当单片机输出字形码时 ,所有数码管都接收到相同的字形码 , 但究竟是哪个数码管会显示出字形 ,取决于单片机对位选通COM端电路的控制 , 所以我们只要将需要显示的数码管的选通控制打开 ,该位就显示出字形 ,没有选通的数码管就不会亮。

      透过分时轮流控制各个LED数码管的COM端 ,就使各个数码管轮流受控显示 , 这就是动态驱动。 在轮流显示过程中 ,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极体的余辉效应 , 尽管实际上各位数码管并非同时点壳 , 但只要扫描的速度足够快 , 给人的印象就是一组稳定的显示资料 ,不会有闪烁感 ,动态显示的效果和静态显示是一样的 , 能够节省大量的I/0口 , 而且功耗更低。

二、控制原理:
      使用动态扫描方式。由于任一时刻只能显示一种数字,当需要多位数码管显示多位数据的时候就需要动态扫描。动态扫描时间上执行的是动态显示,由于动态速度很快,人眼分辨不出,所以看上去是静态显示,这种效果正式我们所需要的。
            
      用这个流程图就能很清晰的了解数码管动态扫描的原理。其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。
三、8位数码管同时点亮 1.在上一课的基础上,新增一个位码选择的数组 2.通过调用数组选择位码 3.新建一个数组选择每个位需要显示的内容      

张旭文 发表于 2024-7-28 21:14:43

一起学习共同进步。

chun1234 发表于 2024-7-30 09:36:04

本帖最后由 chun1234 于 2024-7-30 09:37 编辑

学习冲哥的《STC32G单片机视频教程》   第十一课 定时器的使用

一、学习这一章节 定时器的作用和意义 可以明了以下概念:
      STC32G系列单片机内部设置了5个24位定时器/计数器(8位预分频+16位计数)。5个16位定时器T0、T1、T2、T3和T4都具有计数方式和定时方式两种工作方式。对定时器/计数器TO和T1,用它们在特殊功能寄存器TMOD中相对应的控制位CT来选择TO或T1为定时器还是计数器。对定时器/计数器T2,用特殊功能寄存器AUXR中的控制位T2_C/T来选择T2为定时器还是计数器。对定时器/计数器T3,用特殊功能寄存器T4T3M中的控制位T3_C/T来选择T3为定时器还是计数器。对定时器/计数器T4,用特殊功能寄存器T4T3M中的控制位T4_C/T来选择T4为定时器还是计数器。定时器/计数器的核心部件是一个加法计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚,则为计数方式,每来一个脉冲加1。 本节课主要用T0即timer 0也就是定时器0来实现功能。这个T就是一个定时的一个简称。 以定时器0/1模式寄存器(TMOD)为例: T0 C/T:控制定时器0用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数),置1用作 计数器(对引脚TO/P3.4外部脉冲进行计数)。
       那么,我们为什么要使用定时器呢?回想一下之前写的程序,在实现延时这一功能时,我们使用了delay() 函数,这个函数并没有采用任何外设,只是写了两个循环嵌套,让cpu计数,当计数完成也就代表延时结束,简单点说就是让cpu通过不停的计数来消耗时间,所以这种方式有个很大的弊端,就是当cpu “死跑” 延时的时候,是做不了其他事情的,这个时候就需要一个额外的工具来帮助cpu完成计时,这就是定时器的作用。举个例子,比如你想在十分钟后做某件事,如果身边没有任何工具的话,你只能自己默数600秒,而你在数数的时候是肯定不能分心做其他事情的哈,而如果你身边有块表,那就可以定一个十分钟后的闹钟,让它帮你计时,在这十分钟期间你就可以放心地做其他事情了。   
       定时器还有一些其他作用,比如用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作。注意:定时器的大部分使用场景都要配合中断。
定时器是定时器和计数器的统称。
1)设置为定时器时,可实现硬件计时,或者使程序每隔一固定时间完成一项操作
2)设置为计数器时候能够对脉冲进行计数
3)替代长时间的delay,提高CPU的运行效率和处理速度,能及时的响应某个事件。

二、STC32G单片机定时器使用原理
T0实现1ms中断

2.1 先设置功能为定时器/计数器(本质都是加法计数器)
       STC32G系列单片机内部设置了5个24位定时器/计数器(8位预分频+16位计数)。5个16位定时器T0、T1、T2、T3和T4都具有计数方式和定时方式两种工作方式。对定时器/计数器TO和T1,用它们在特殊功能寄存器TMOD中相对应的控制位CT来选择TO或T1为定时器还是计数器。对定时器/计数器T2,用特殊功能寄存器AUXR中的控制位T2_C/T来选择T2为定时器还是计数器。对定时器/计数器T3,用特殊功能寄存器T4T3M中的控制位T3_C/T来选择T3为定时器还是计数器。对定时器/计数器T4,用特殊功能寄存器T4T3M中的控制位T4_C/T来选择T4为定时器还是计数器。定时器/计数器的核心部件是一个加法计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚,则为计数方式,每来一个脉冲加1。
本节课主要用T0即timer 0也就是定时器0来实现功能。这个T就是一个定时的一个简称。
       以定时器0/1模式寄存器(TMOD)为例:
       T0 C/T:控制定时器0用作定时器或计数器,清0则用作定时器(对内部系统时钟进行计数),置1用作
       计数器(对引脚TO/P3.4外部脉冲进行计数)。

2.2、在定时器模式下,设置不分频或者12分频∶
       当定时器/计数器TO、T1及T2工作在定时模式时,特殊功能寄存器AUXR中的TOx12、T1x12和T2x12分别决定是系统时钟/12还是系统时钟/1(不分频)后让TO、T1和T2进行计数。当定时器/计数器T3和T4工作在定时模式时,特殊功能寄存器T4T3M中的T3x12和T4x12分别决定是系统时钟/12还是系统时钟/1(不分频)后让T3和T4进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。
定时方式,此时定时器/计数器每12个时钟或者每1个时钟得到一个计数脉冲,计数值加1; 计数差了12倍。默认是除以12的。

2.3、定时器的工作模式
STC32G单片机的定时器0~定时器4工作模式以下表形式说明:
   
         

2.4、定时器设置

       STC32G单片机有T0~T4共5个通用定时器。定时器核心器件是一个加法计数器,其本质是对脉冲计数。计数脉冲来自系统时钟,定时器工作在定时方式(因为系统时钟是一定的,因而计数器寄存器溢出的时间是可预期的)。定时器的计数脉冲来自外部引脚,则工作在计数器方式。定时器的工作模式可以通过对相应寄存器的C/T位置1或置0来进行设置,如:T0是对TMOD寄存器的B2(T0_CT)位进行设置,置0就工作在定时方式,置1就工作在计数器方式。T1是对TMOD寄存器的B6(T1_CT)位进行设置,置0就工作在定时方式,置1就工作在计数器方式。T2是对AUXR寄存器的B3(T2_CT)位进行设置,置0就工作在定时方式,置1就工作在计数器方式。T3是对T4T3M寄存器的B2(T3_CT)位进行设置,置0就工作在定时方式,置1就工作在计数器方式。T4是对T4T3M寄存器的B2(T3_CT)位进行设置,置0就工作在定时方式,置1就工作在计数器方式。

2.5、中断

EA:总中断允许控制位。EA的作用是使中断允许形成多级控制,即各中断源首先受EA控制,其次还受各中断源自己的中断允许控制位控制,
       0:CPU屏蔽所有的中断申请
       1:CPU开发中断
ELVD: 低压检测中断允许位。
          0:禁止低压检测中断
          1:允许低压检测中断
EADC:A/D转换中断允许位。
         0:禁止A/D转换中断
         1:允许A/D转换中断
ES: 串行口1中断允许位。
      0:进制串行口1中断
      1:允许串行口1中断
ET1: 定时/计数器T1的溢出中断允许位。
      0:禁止T1中断
      1:允许T1中断
EX1: 外部中断1 中断允许位。
      0:禁止INT1中断
      1:允许INT1中断
ET0:定时/计数器T0的溢出中断允许位。
      0:禁止T1中断
      1:允许T1中断
EX0: 外部中断0中断允许位。
      0:禁止INT1中断
      1:允许INT1中断



chun1234 发表于 2024-8-3 09:05:58

本帖最后由 chun1234 于 2024-8-3 09:25 编辑

学习冲哥的《STC32G单片机视频教程》   第十二课 计数器的使用   

一、计数器的用途

      只要输出信号带高低电平变化的,需要计算个数的就可以用计数器的功能。

二、计数器的配置
       计数器0与计数器1有多种模式可以通过软件配置,而计数器2/3/4 只有16位自动重装载模式。计数器0与计数器1有多种模式为:
       TMOD=0x04: 计数器0-模式0-16位自动重装载模式
       TMOD=0x05: 计数器0-模式1-16位不可重装载模式
       TMOD=0x06: 计数器0-模式2-8位自动重装载模式
       TMOD=0X07: 计数器0-模式3-不可屏蔽中断16位重装载模式
       TMOD=0x40: 计数器1-模式 0-16位自动重装载模式
       TMOD=0x50: 计数器1-模式1-16位不可重装载模式
       TMOD=ox60: 计数器0-模式2-8位自动重装载模式

       根据冲哥的视频教程,用下面的代码来验证一下:

       #include "COMM/stc.h"                //调用头文件

       #include "COMM/usb.h"

       #define KEY1 P32                     //定义一个按键 引脚选择P32       #define KEY2 P33                     //定义一个按键 引脚选择P33       #define BEEP P54                     //定义一个按键 引脚选择P54       #define SEG_Delay1               //延时多少ms
      #define MAIN_Fosc 24000000UL//定义主时钟
      char *USER_DEVICEDESC = NULL;      char *USER_PRODUCTDESC = NULL;      char *USER_STCISPCMD = "@STCISP#";
      u32 TimCount = 0;                      //计数单位1ms      bit RUN_State = 0;                      //开始运行/结束运行      u8 num = 0;
      void sys_init();                           //函数声明      void delay_ms(u16 ms);            //unsigned int
      void main()                              //程序开始运行的入口      {
            sys_init();                               //USB功能+IO口初始化            usb_init();                              //usb库初始化
            TMOD = 0x40;                     //设置计数器模式            TL1 = 0xFF;                           //设置计数初始值            TH1 = 0xFF;                           //设置计数初始值            TF1 = 0;                              //清除TF1标志            TR1 = 1;                              //定时器1开始计时            ET1 = 1;                              //使能定时器1中断
            P3PU = 0x20;                         //打开内部上拉4.1K
         Timer0_Init();            P40 = 0;                              //led的电源控制三极管打开
            EA = 1;                                 //CPU开放中断,打开总中断。
            while(1)                              //死循环            {                if( DeviceState != DEVSTATE_CONFIGURED )         //                        continue;                if( bUsbOutReady )                                                                                {                        usb_OUT_done();
                }                         }   }

    void Timer0_Isr(void) interrupt 3    {      P60 = !P60;                              //led取反    }
    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;    //设置为准双向口
         P3M0 = 0x00;         P3M1 = 0x00;
         P3M0 &= ~0x03;         P3M1 |= 0x03;
         //设置USB使用的时钟源         IRC48MCR = 0x80;                     //使能内部48M高速IRC         while (!(IRC48MCR & 0x01));       //等待时钟稳定
         USBCLK = 0x00;                        //使用CDC功能需要使用这两行,HID功能禁用这两行。         USBCON = 0x90;    }
    void delay_ms(u16 ms)                   //unsigned int     {         u16 i;         do         {                i = MAIN_Fosc/6000;                while(--i);         }while(--ms);    }
       对以上代码的反复实验,了解到:通过用按键KEY1来模拟下降沿的脉冲,使定时器1接收到,定时器1开始计数。每按下一次按键,P60端口的LED即反转一次,由于按键没有加消除抖动的延时,存在一些误动作。



chun1234 发表于 2024-8-6 15:39:02

本帖最后由 chun1234 于 2024-8-6 17:14 编辑

学习冲哥的《STC32G单片机视频教程》   第十三课 简易多任务处理
一、回顾:通过前一段时间的学习,已经跟着冲哥的视频课程学习了12个章节                   1、认识单片机                   2、了解单片机硬件                   3、开发环境搭建、新工程建立和资料下载                   4、点亮一个LED                   5、C语言运算符和进制入门                   6、LED闪烁和花式点灯                   7、按键点亮灯                   8、蜂鸣器的使用                   9、数码管的静态使用                  10、数码管的动态点亮                  11、定时器                  12、计数器的使用
            对于单片机内部功能的使用,用到了 GPIO 和TIM,同时了解到什么时候打开LED? LED打开多久?什么时候切换数码管显示?什么时候按键按下触发什么功能?之前的课主要是学习写程序的方法,分析逻辑,实现我们要的功能,重点是理清程序的逻辑思路。从这一节课开始,我们要规范所写的程序,也就是所写的代码要规范。
二、应用模块化的编程 (.c + .h)       1、LED& 数码管      对应      led_seg.c,led_seg.h       2、按键                      对应      key.c, key.h       3、蜂鸣器                   对应      beep.c, beep.h       4、定时器                   对应      tim.c, tim.h
三、具体的操作步骤:
          1、分三步创建程序文件                   新建文件并保存                   添加到工程                   添加引用路径
          2、引脚定义都在.h文件                   sbit 名称 = P10;                   #define 名称 P10
          3、函数定义三步                   定义                   声明                   调用
         修饰符extern用在变量或者函数的声明前,用来说明 “此变量/函数是在别处定义的,要在此处引用” 。         注意:extern修饰的变量不能赋初值。
四、工程文件编写
                由原理图得知:8个LED的负极与数码管的8个段选控制端公用P6端口,所以给他们放在了一个文件(led_seg.c和led_seg.h)。                之前的程序是在定时器中通过一个函数刷新数码管,现在就要给他增加刷新LED的功能。在这里刷新显示,在别的地方赋值。
               截图如下:
void SEG_Fre( void )
{
      //位码选择第一位,段码选择0
      P7 = COM_Tab;             //位码的选择
      P6 = SEG_Tab];       //需要显示的数字的内码 赋给 P6NUM =0 -> Show_Tab] = 1 -> p6 = oxF9
      delay_ms(SEG_Delay);

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


chun1234 发表于 2024-8-16 10:04:49

本帖最后由 chun1234 于 2024-8-16 10:26 编辑

学习冲哥的《STC32G单片机视频教程》 第十四课 矩阵按键

一、矩阵按键是什么:采用行列矩阵的方式排列按键,再用扫描法识别按键。
二、识别原理:端口默认为高电平,实时读取到引脚为低电平时表示按下。
第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
第三步:行列组合一下就可以判断出是哪一个按键按下了。

三、矩阵按键用数码管显示按键号的代码如下:
#include "COMM/stc.h"                               //调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"
#include "beep.h"
#include "tim0.h"

#define MAIN_Fosc 24000000UL               //定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

bitTIM_10MS_Flag;                        //10ms的标志位

void sys_init();                                       //函数声明
void delay_ms(u16 ms);                            //unsigned int

void main()                                              //程序开始运行的入口
{
      u8 KEY_NUM = 0;                                    //保存矩阵按键的键码
      u8 KEY_Str = 0;                                    //表示当前输入了几个密码位
      
      sys_init();                                             //USB功能+IO口初始化
      usb_init();                                              //usb库初始化

      Timer0_Init();
      EA = 1;                                                //CPU开放中断,打开总中断。
      
//      SEG0 = 0;
//      SEG1 = 1;
//      SEG2 = 2;
//      SEG3 = 3;
//      SEG4 = 4;
//      SEG5 = 5;
//      SEG6 = 6;
//      SEG7 = 7;
      
      LED = 0xff;                                             //初始状态熄灭所有LED
      
      while(1)                                                 //死循环
      {
                if( DeviceState != DEVSTATE_CONFIGURED )         //
                        continue;
                if( bUsbOutReady )                                                               
                {
                        usb_OUT_done();
                }
               
                if( TIM_10MS_Flag==1 )                        //如果10ms到了
                {
                        TIM_10MS_Flag = 0;                           //清空标志位
//                        KEY_Deal();                                    //按键处理
                        BEEP_RUN();                                        //蜂鸣运行

                        KEY_NUM = MateixKEY_Read();             //当前矩阵按键的键值
                        if( KEY_NUM>0 )                                  //如果有按键按下
                        {
                              BEEP_ON(2);                                       //蜂鸣20ms
                              Show_Tab = KEY_NUM;          //将当前的按键的键值保存到数码管显示变量里
                              KEY_Str ++;                                       //s输入的密码位数+1
                              
                              if( KEY_Str == 8 )                               //如果密码已经输到了8位
                              {
                                        KEY_Str = 0;                                    //清空当前密码的位数
                                        //for
                                        if((Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1)&&(Show_Tab==1))       //如果密码正确
                                        {
                                                LED0= 0;                                       //点亮LED0
                                        }
                                        else
                                        {
                                                BEEP_ON(200);                                 //密码错误,蜂鸣2秒
                                        }
                                        SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 =SEG6 = SEG7 = 21;       //将所有的数码管显示位 -
                              }
                              KEY_NUM = 0;                                 //清空按键键值
                        }

                }
      }
}

void Timer0_Isr(void) interrupt 1
{
      static timcount = 0;
      
      SEG_LED_Show();                         //数码管刷新的
      
      timcount++;                                 //1ms+1
      if( timcount>=10 )                        //如果这个变量大于等于10,10ms计数到达
      {
                timcount = 0;
                TIM_10MS_Flag = 1;                  //10ms时间到了
      }
}

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;       //设置为准双向口
      
    P3M0 = 0x00;
    P3M1 = 0x00;
   
    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;                  //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));      //等待时钟稳定

    USBCLK = 0x00;                        //使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}

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

以上代码已经实验通过。体会到矩阵按键可以节省单片机的 IO 口,代码编写起来稍微费一些事,与独立按键相比,各有优缺点。

chun1234 发表于 2024-8-21 16:30:55

本帖最后由 chun1234 于 2024-8-21 16:36 编辑

学习冲哥的《STC32G单片机视频教程》   第十五课 外部中断
一、中断和中断系统      当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。      能够实现上述功能的部件,称为中断系统。请示CPU中断的请求源称为中断源。微型机的中断系统一般允许有多个中断源。CPU总是先响应优先级别最高的中断请求。
二、什么是外部中断       外部中断的产生通常是由于外部设备或环境的变化触发的,这些变化可能是物理按键的按下、传感器读数的改变、或者其他外部信号的变化。当这些变化发生时,单片机通过中断系统接收到这些信号,并暂停当前程序的执行,跳转到相应的中断服务程序进行处理。处理完成后,单片机再返回到被中断的程序继续执行。

三、外部中断的用法       1、‌实时处理功能‌:在实时控制中,外部中断可以随时响应外界变量的变化,如参数、信息的实时变化,向CPU发出中断申请,请求及时处理。例如,当某个外部设备需要CPU立即响应时,可以通过外部中断请求CPU中断当前任务,转而处理外部设备的请求。      2、‌故障处理功能‌:对于难以预料的情况或故障,如掉电、存储出错、运算溢出等,外部中断可以由故障源向CPU发出中断请求,CPU随后转到相应的故障处理程序进行处理。这种机制对于保障系统的稳定性和可靠性至关重要。 3、‌分时操作‌:外部中断可以解决CPU与慢速外设之间的矛盾,使CPU和外设同时工作。CPU在启动外设工作后继续执行主程序,外设完成工作后通过发出中断申请请求CPU处理。这种方式大大提高了CPU的效率,允许同时处理多个任务。

四、中断系统包含哪些中断源      主要的中断源有 外部中断 (INT0) (INT1) (INT3) (INT4)                               定时器中断(Timer0) (Timer1) (Timer2) (Timer3)                              串口中断 (UART1) (UART2) (UART3) (UART4)

五、中断的优先级 需要查阅手册,确定中断的优先级

六、这一节课的代码练习:
#include "COMM/stc.h"                //调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"
#include "beep.h"
#include "tim0.h"
#include "exit.h"

#define MAIN_Fosc 24000000UL      //定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

bitTIM_10MS_Flag;                        //10ms的标志位

void sys_init();      //函数声明
void delay_ms(u16 ms);      //unsigned int


void main()                                        //程序开始运行的入口
{
      u8 i;
      u8 KEY_NUM = 0;                        //保存矩阵按键的键码
      u8 KEY_Str = 0;                        //表示当前输入了几个密码位
      
      sys_init();                                 //USB功能+IO口初始化
      usb_init();                                 //usb库初始化

      Timer0_Init();                               //定时器0初始化
      INT0_Init();                                  //外部中断0初始化
      
      EA = 1;                                        //CPU开放中断,打开总中断。
      
      SEG0 = 0;
      SEG1 = 0;
//      SEG2 = 2;
//      SEG3 = 3;
//      SEG4 = 4;
//      SEG5 = 5;
//      SEG6 = 6;
//      SEG7 = 7;
      
      LED = 0xff;                              //初始状态熄灭所有LED
      
      while(1)                            //死循环
      {
                if( DeviceState != DEVSTATE_CONFIGURED )         //
                        continue;
                if( bUsbOutReady )                                                               
                {
                        usb_OUT_done();
                }

                for(i=0;i<8;i++)                     //循环八次
                {
                        LED = ~(1<<i);                //当前i是几,就点亮第几个LED
                        delay_ms(500);                //延时500ms
                }
                if( P33 ==0 )                           //如果P33按下了
                        SEG1 += 1;                     //数码管1的数值+1
               
      }
}

void INT0_Isr(void) interrupt 0
{
      SEG0 += 1;                                        //数码管0的数值+1
}


void Timer0_Isr(void) interrupt 1
{
      static timcount = 0;
      
      SEG_LED_Show();                        //数码管刷新的
      
      timcount++;                              //1ms+1
      if( timcount>=10 )                     //如果这个变量大于等于10,10ms计数到达
      {
                timcount = 0;
                TIM_10MS_Flag = 1;            //10ms时间到了
      }
}

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;   //设置为准双向口
      
    P3M0 = 0x00;
    P3M1 = 0x00;
   
    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));//等待时钟稳定

    USBCLK = 0x00;      //使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}

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


chun1234 发表于 2024-8-25 15:18:04

本帖最后由 chun1234 于 2024-8-25 15:35 编辑

学习冲哥的《STC32G单片机视频教程》   第十六课 IO中断
一、普通I/O口均可中断,不是传统外部中断STC32G系列支持所有的I/O口中断,且支持4种中断模式:下降沿中断、上升沿中断、低电平中断和高电平中断。每组I/O口都有独立的中断入口地址,且每个I/O口可独立设置中断模式。

二、I/O中断的用法

#include "COMM/stc.h"                //调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"
#include "beep.h"
#include "tim0.h"
#include "exit.h"


#define MAIN_Fosc 24000000UL      //定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

bitTIM_10MS_Flag;                        //10ms的标志位
u16 Tme_CountDown = 0;                //全局变量

void sys_init();                        //函数声明
void delay_ms(u16 ms);                //unsigned int

void main()                                        //程序开始运行的入口
{
      u8 LOCK_State = 0xff;      //门锁的工作状态
      u8 KEY_NUM = 0;                        //保存矩阵按键的键码
      u8 KEY_Str = 0;                        //表示当前输入了几个密码位
      
      sys_init();                              //USB功能+IO口初始化
      usb_init();                              //usb库初始化

      Timer0_Init();                        //定时器0初始化
      INT0_Init();                        //外部中断0初始化
      P3Exit_Init();
      
      EA = 1;                                        //CPU开放中断,打开总中断。
      
      SEG0 = 0;
      
      LED = LOCK_State;                //初始状态熄灭所有LED
      
      while(1)                              //死循环
      {
                if( DeviceState != DEVSTATE_CONFIGURED )         //
                        continue;
                if( bUsbOutReady )                                                               
                {
                        usb_OUT_done();
                }
               
                if( TIM_10MS_Flag==1 )                                                                        //如果10ms到了
                {
                        TIM_10MS_Flag = 0;                                                                        //清空标志位
                        
                        if( Tme_CountDown==0 )                                                                //如果没有按下过应急按钮
                        {
                              KEY_NUM = MateixKEY_Read();                                                //当前矩阵按键的键值1-8
                              BEEP_RUN();                                                                              //蜂鸣运行
                              if( KEY_NUM>0 )                                                                        //如果有按键拿下
                              {
                                        BEEP_ON(2);
                                        LOCK_State ^=(1<<(KEY_NUM-1));                        //获取当前是第几个按钮按下,{1-8}-》
                              }
                              LED = LOCK_State;                                                                //初始状态熄灭所有LED
                              SEG0 = 20;                                                                              //熄灭数码管
                        }
                        else                                                                                                //按下了应急按钮
                        {
                              Tme_CountDown--;
                              SEG0 = (Tme_CountDown/100+1);                                        //500/100 499
                        }
                }               
      }
}

void INT0_Isr(void) interrupt 0
{
}

void P3Exit_Isr(void) interrupt 40
{
      u8 intf;
      intf = P3INTF;                              //读取中断标志
      if( intf )
      {
                P3INTF = 0;                              //清空中断标志位,必须软件清空
                if( intf & 0x20 )                //p35按下 0010 0000
                {
                        LED = 0x00;                        //打开所有门锁
                        SEG0 = 5;                        //数码管持续显示5
                        Tme_CountDown = 500;//5秒倒计时的一个变脸
                }
      }
}
void Timer0_Isr(void) interrupt 1
{
      static timcount = 0;
      
      SEG_LED_Show();                        //数码管刷新的
      
      timcount++;                              //1ms+1
      if( timcount>=10 )                //如果这个变量大于等于10,10ms计数到达
      {
                timcount = 0;
                TIM_10MS_Flag = 1;      //10ms时间到了
      }
}

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;   //设置为准双向口
      
    P3M0 = 0x00;
    P3M1 = 0x00;
   
    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;                            //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));          //等待时钟稳定

    USBCLK = 0x00;      //使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}

void delay_ms(u16 ms)      //unsigned int
{
      u16 i;
      do
      {
                i = MAIN_Fosc/6000;
                while(--i);
      }while(--ms);
}
三、中断优先级的设置相同优先级,考前的中断源先执行,执行完之后再执行低中断源,且一个中断源在执行的时候不能被打断。例如:定时器0和P3中断都是最低优先级,定时器0中断号1;P3中断号40,执行完定时器0,再执行P3,之后再执行定时器0。

阿杰爱学单片机 发表于 2024-8-25 22:10:06

chun1234 发表于 2024-7-23 15:47
学习冲哥的《STC32G单片机视频教程》      第八课   蜂鸣器的应用

一、认识蜂鸣器:


看了你的帖子,我感觉我在假学习,实验会做 ,就是写不出你这种帖子{:4_171:}
页: 1 [2] 3
查看完整版本: 学习冲哥视频 《32位8051单片机原理及应用》打卡