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

学习冲哥视频 《32位8051单片机原理及应用》打卡

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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个发光的二极管有一个公共端,这样就可以控制一位数码管整体,这就是段选。
       由一位数码管延伸到四位数码管时,如图所示,每一个发光管都有相应的引脚控制,每一位的数码管都有自己的公共端,通过公共端来控制哪一位的数码管亮或者是灭,这就是位选。

         

图9-1

图9-1

        单片机的P6.0~P6.6引脚分别接到数码管的a~g引脚,就可以通过控制P6各引脚电平的高低来控制数码管七段LED的亮灭;单片机的P7.0~P7.7分别通过8PNP型三极管,驱动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[10] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 };        //0-9
/*
数组内16进制与2进制与实际显示数字对照:
0xc0  1100 0000 ---> 0
0xf9  1111 1001 ---> 1
0xa4  1010 0100 ---> 2
0xb0  1011 0000 ---> 3
0x99  1001 1001 ---> 4
0x92  1001 0010 ---> 5
0x82  1000 0010 ---> 6
0xf8  1111 1000 ---> 7
0x80  1000 0000 ---> 8
0x90  1001 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[num];         //这个数码管输出段码
                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);
}





回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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口 , 而且功耗更低。

二、控制原理:

        使用动态扫描方式。由于任一时刻只能显示一种数字,当需要多位数码管显示多位数据的时候就需要动态扫描。动态扫描时间上执行的是动态显示,由于动态速度很快,人眼分辨不出,所以看上去是静态显示,这种效果正式我们所需要的。

             10-1.png

        用这个流程图就能很清晰的了解数码管动态扫描的原理。其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。

三、8位数码管同时点亮
1.在上一课的基础上,新增一个位码选择的数组
2.通过调用数组选择位码
3.新建一个数组选择每个位需要显示的内容
        

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:19
  • 最近打卡:2024-08-22 07:09:06

4

主题

36

回帖

170

积分

注册会员

积分
170
发表于 2024-7-28 21:14:43 | 显示全部楼层
一起学习共同进步。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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工作模式以下表形式说明:
   
          11-1定时器.png

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中断



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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_Delay  1                 //延时多少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即反转一次,由于按键没有加消除抖动的延时,存在一些误动作。




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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的功能。在这里刷新显示,在别的地方赋值。

               截图如下:

  1. void SEG_Fre( void )
  2. {
  3.         //位码选择第一位,段码选择0  
  4.         P7 = COM_Tab[num];             //位码的选择
  5.         P6 = SEG_Tab[Show_Tab[num]];       //需要显示的数字的内码 赋给 P6  NUM =0 -> Show_Tab[num]] = 1 -> p6 = oxF9
  6.         delay_ms(SEG_Delay);
  7.         num++;
  8.         if( num >7 )
  9.                 num = 0;        
  10. }
复制代码


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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就会变成低电平,就可以判断出哪一行按下了。

第三步:行列组合一下就可以判断出是哪一个按键按下了。


三、矩阵按键用数码管显示按键号的代码如下

  1. #include "COMM/stc.h"                               //调用头文件
  2. #include "COMM/usb.h"
  3. #include "seg_led.h"
  4. #include "key.h"
  5. #include "beep.h"
  6. #include "tim0.h"
  7. #define MAIN_Fosc 24000000UL                 //定义主时钟
  8. char *USER_DEVICEDESC = NULL;
  9. char *USER_PRODUCTDESC = NULL;
  10. char *USER_STCISPCMD = "@STCISP#";
  11. bit  TIM_10MS_Flag;                        //10ms的标志位
  12. void sys_init();                                         //函数声明
  13. void delay_ms(u16 ms);                            //unsigned int
  14. void main()                                              //程序开始运行的入口
  15. {
  16.         u8 KEY_NUM = 0;                                    //保存矩阵按键的键码
  17.         u8 KEY_Str = 0;                                      //表示当前输入了几个密码位
  18.         
  19.         sys_init();                                               //USB功能+IO口初始化
  20.         usb_init();                                              //usb库初始化
  21.         Timer0_Init();
  22.         EA = 1;                                                  //CPU开放中断,打开总中断。
  23.         
  24. //        SEG0 = 0;
  25. //        SEG1 = 1;
  26. //        SEG2 = 2;
  27. //        SEG3 = 3;
  28. //        SEG4 = 4;
  29. //        SEG5 = 5;
  30. //        SEG6 = 6;
  31. //        SEG7 = 7;
  32.         
  33.         LED = 0xff;                                             //初始状态熄灭所有LED
  34.         
  35.         while(1)                                                 //死循环
  36.         {
  37.                 if( DeviceState != DEVSTATE_CONFIGURED )         //
  38.                         continue;
  39.                 if( bUsbOutReady )                                                               
  40.                 {
  41.                         usb_OUT_done();
  42.                 }
  43.                
  44.                 if( TIM_10MS_Flag==1 )                        //如果10ms到了
  45.                 {
  46.                         TIM_10MS_Flag = 0;                             //清空标志位
  47. //                        KEY_Deal();                                      //按键处理
  48.                         BEEP_RUN();                                        //蜂鸣运行
  49.                         KEY_NUM = MateixKEY_Read();             //当前矩阵按键的键值
  50.                         if( KEY_NUM>0 )                                  //如果有按键按下
  51.                         {
  52.                                 BEEP_ON(2);                                       //蜂鸣20ms
  53.                                 Show_Tab[KEY_Str] = KEY_NUM;          //将当前的按键的键值保存到数码管显示变量里
  54.                                 KEY_Str ++;                                       //s输入的密码位数+1
  55.                                 
  56.                                 if( KEY_Str == 8 )                               //如果密码已经输到了8位
  57.                                 {
  58.                                         KEY_Str = 0;                                      //清空当前密码的位数
  59.                                         //for
  60.                                         if((Show_Tab[0]==1)&&(Show_Tab[1]==1)&&(Show_Tab[2]==1)&&(Show_Tab[3]==1)&&(Show_Tab[4]==1)&&(Show_Tab[5]==1)&&(Show_Tab[6]==1)&&(Show_Tab[7]==1))       //如果密码正确
  61.                                         {
  62.                                                 LED0  = 0;                                         //点亮LED0
  63.                                         }
  64.                                         else
  65.                                         {
  66.                                                 BEEP_ON(200);                                 //密码错误,蜂鸣2秒
  67.                                         }
  68.                                         SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 =SEG6 = SEG7 = 21;       //将所有的数码管显示位 -
  69.                                 }
  70.                                 KEY_NUM = 0;                                 //清空按键键值
  71.                         }
  72.                 }
  73.         }
  74. }
  75. void Timer0_Isr(void) interrupt 1
  76. {
  77.         static timcount = 0;
  78.         
  79.         SEG_LED_Show();                         //数码管刷新的
  80.         
  81.         timcount++;                                 //1ms+1
  82.         if( timcount>=10 )                        //如果这个变量大于等于10,10ms计数到达
  83.         {
  84.                 timcount = 0;
  85.                 TIM_10MS_Flag = 1;                    //10ms时间到了
  86.         }
  87. }
  88. void sys_init()                              //函数定义
  89. {
  90.     WTST = 0;                                 //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  91.     EAXFR = 1;                                //扩展寄存器(XFR)访问使能
  92.     CKCON = 0;                               //提高访问XRAM速度
  93.     P0M1 = 0x00;   P0M0 = 0x00;       //设置为准双向口
  94.     P1M1 = 0x00;   P1M0 = 0x00;       //设置为准双向口
  95.     P2M1 = 0x00;   P2M0 = 0x00;       //设置为准双向口
  96.     P3M1 = 0x00;   P3M0 = 0x00;       //设置为准双向口
  97.     P4M1 = 0x00;   P4M0 = 0x00;       //设置为准双向口
  98.     P5M1 = 0x00;   P5M0 = 0x00;       //设置为准双向口
  99.     P6M1 = 0x00;   P6M0 = 0x00;       //设置为准双向口
  100.     P7M1 = 0x00;   P7M0 = 0x00;       //设置为准双向口
  101.         
  102.     P3M0 = 0x00;
  103.     P3M1 = 0x00;
  104.    
  105.     P3M0 &= ~0x03;
  106.     P3M1 |= 0x03;
  107.     //设置USB使用的时钟源
  108.     IRC48MCR = 0x80;                    //使能内部48M高速IRC
  109.     while (!(IRC48MCR & 0x01));      //等待时钟稳定
  110.     USBCLK = 0x00;                        //使用CDC功能需要使用这两行,HID功能禁用这两行。
  111.     USBCON = 0x90;
  112. }
  113. void delay_ms(u16 ms)                                //unsigned int
  114. {
  115.         u16 i;
  116.         do
  117.         {
  118.                 i = MAIN_Fosc/6000;
  119.                 while(--i);
  120.         }while(--ms);
  121. }
复制代码

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


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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)


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


六、这一节课的代码练习:

  1. #include "COMM/stc.h"                //调用头文件
  2. #include "COMM/usb.h"
  3. #include "seg_led.h"
  4. #include "key.h"
  5. #include "beep.h"
  6. #include "tim0.h"
  7. #include "exit.h"
  8. #define MAIN_Fosc 24000000UL        //定义主时钟
  9. char *USER_DEVICEDESC = NULL;
  10. char *USER_PRODUCTDESC = NULL;
  11. char *USER_STCISPCMD = "@STCISP#";
  12. bit  TIM_10MS_Flag;                        //10ms的标志位
  13. void sys_init();        //函数声明
  14. void delay_ms(u16 ms);        //unsigned int
  15. void main()                                        //程序开始运行的入口
  16. {
  17.         u8 i;
  18.         u8 KEY_NUM = 0;                        //保存矩阵按键的键码
  19.         u8 KEY_Str = 0;                          //表示当前输入了几个密码位
  20.         
  21.         sys_init();                                   //USB功能+IO口初始化
  22.         usb_init();                                   //usb库初始化
  23.         Timer0_Init();                               //定时器0初始化
  24.         INT0_Init();                                  //外部中断0初始化
  25.         
  26.         EA = 1;                                        //CPU开放中断,打开总中断。
  27.         
  28.         SEG0 = 0;
  29.         SEG1 = 0;
  30. //        SEG2 = 2;
  31. //        SEG3 = 3;
  32. //        SEG4 = 4;
  33. //        SEG5 = 5;
  34. //        SEG6 = 6;
  35. //        SEG7 = 7;
  36.         
  37.         LED = 0xff;                                //初始状态熄灭所有LED
  38.         
  39.         while(1)                            //死循环
  40.         {
  41.                 if( DeviceState != DEVSTATE_CONFIGURED )         //
  42.                         continue;
  43.                 if( bUsbOutReady )                                                               
  44.                 {
  45.                         usb_OUT_done();
  46.                 }
  47.                 for(i=0;i<8;i++)                       //循环八次
  48.                 {
  49.                         LED = ~(1<<i);                //当前i是几,就点亮第几个LED
  50.                         delay_ms(500);                //延时500ms
  51.                 }
  52.                 if( P33 ==0 )                           //如果P33按下了
  53.                         SEG1 += 1;                     //数码管1的数值+1
  54.                
  55.         }
  56. }
  57. void INT0_Isr(void) interrupt 0
  58. {
  59.         SEG0 += 1;                                        //数码管0的数值+1
  60. }
  61. void Timer0_Isr(void) interrupt 1
  62. {
  63.         static timcount = 0;
  64.         
  65.         SEG_LED_Show();                        //数码管刷新的
  66.         
  67.         timcount++;                                //1ms+1
  68.         if( timcount>=10 )                       //如果这个变量大于等于10,10ms计数到达
  69.         {
  70.                 timcount = 0;
  71.                 TIM_10MS_Flag = 1;            //10ms时间到了
  72.         }
  73. }
  74. void sys_init()                //函数定义
  75. {
  76.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  77.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  78.     CKCON = 0; //提高访问XRAM速度
  79.     P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  80.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  81.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  82.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  83.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  84.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  85.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  86.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  87.         
  88.     P3M0 = 0x00;
  89.     P3M1 = 0x00;
  90.    
  91.     P3M0 &= ~0x03;
  92.     P3M1 |= 0x03;
  93.     //设置USB使用的时钟源
  94.     IRC48MCR = 0x80;    //使能内部48M高速IRC
  95.     while (!(IRC48MCR & 0x01));  //等待时钟稳定
  96.     USBCLK = 0x00;        //使用CDC功能需要使用这两行,HID功能禁用这两行。
  97.     USBCON = 0x90;
  98. }
  99. void delay_ms(u16 ms)        //unsigned int
  100. {
  101.         u16 i;
  102.         do
  103.         {
  104.                 i = MAIN_Fosc/6000;
  105.                 while(--i);
  106.         }while(--ms);
  107. }
复制代码


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:318
  • 最近打卡:2025-07-01 07:37:52

3

主题

34

回帖

965

积分

高级会员

积分
965
发表于 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中断的用法


  1. #include "COMM/stc.h"                //调用头文件
  2. #include "COMM/usb.h"
  3. #include "seg_led.h"
  4. #include "key.h"
  5. #include "beep.h"
  6. #include "tim0.h"
  7. #include "exit.h"
  8. #define MAIN_Fosc 24000000UL        //定义主时钟
  9. char *USER_DEVICEDESC = NULL;
  10. char *USER_PRODUCTDESC = NULL;
  11. char *USER_STCISPCMD = "@STCISP#";
  12. bit  TIM_10MS_Flag;                        //10ms的标志位
  13. u16 Tme_CountDown = 0;                //全局变量
  14. void sys_init();                        //函数声明
  15. void delay_ms(u16 ms);                //unsigned int
  16. void main()                                        //程序开始运行的入口
  17. {
  18.         u8 LOCK_State = 0xff;        //门锁的工作状态
  19.         u8 KEY_NUM = 0;                        //保存矩阵按键的键码
  20.         u8 KEY_Str = 0;                        //表示当前输入了几个密码位
  21.         
  22.         sys_init();                                //USB功能+IO口初始化
  23.         usb_init();                                //usb库初始化
  24.         Timer0_Init();                        //定时器0初始化
  25.         INT0_Init();                        //外部中断0初始化
  26.         P3Exit_Init();
  27.         
  28.         EA = 1;                                        //CPU开放中断,打开总中断。
  29.         
  30.         SEG0 = 0;
  31.         
  32.         LED = LOCK_State;                //初始状态熄灭所有LED
  33.         
  34.         while(1)                                //死循环
  35.         {
  36.                 if( DeviceState != DEVSTATE_CONFIGURED )         //
  37.                         continue;
  38.                 if( bUsbOutReady )                                                               
  39.                 {
  40.                         usb_OUT_done();
  41.                 }
  42.                
  43.                 if( TIM_10MS_Flag==1 )                                                                        //如果10ms到了
  44.                 {
  45.                         TIM_10MS_Flag = 0;                                                                        //清空标志位
  46.                         
  47.                         if( Tme_CountDown==0 )                                                                //如果没有按下过应急按钮
  48.                         {
  49.                                 KEY_NUM = MateixKEY_Read();                                                //当前矩阵按键的键值  1-8
  50.                                 BEEP_RUN();                                                                                //蜂鸣运行
  51.                                 if( KEY_NUM>0 )                                                                        //如果有按键拿下
  52.                                 {
  53.                                         BEEP_ON(2);
  54.                                         LOCK_State ^=  (1<<(KEY_NUM-1));                        //获取当前是第几个按钮按下,{1-8}-》
  55.                                 }
  56.                                 LED = LOCK_State;                                                                //初始状态熄灭所有LED
  57.                                 SEG0 = 20;                                                                                //熄灭数码管
  58.                         }
  59.                         else                                                                                                //按下了应急按钮
  60.                         {
  61.                                 Tme_CountDown--;
  62.                                 SEG0 = (Tme_CountDown/100+1);                                        //500/100 499
  63.                         }
  64.                 }               
  65.         }
  66. }
  67. void INT0_Isr(void) interrupt 0
  68. {
  69. }
  70. void P3Exit_Isr(void) interrupt 40
  71. {
  72.         u8 intf;
  73.         intf = P3INTF;                                //读取中断标志
  74.         if( intf )
  75.         {
  76.                 P3INTF = 0;                                //清空中断标志位,必须软件清空
  77.                 if( intf & 0x20 )                //p35按下 0010 0000
  78.                 {
  79.                         LED = 0x00;                        //打开所有门锁
  80.                         SEG0 = 5;                        //数码管持续显示5
  81.                         Tme_CountDown = 500;//5秒倒计时的一个变脸
  82.                 }
  83.         }
  84. }
  85. void Timer0_Isr(void) interrupt 1
  86. {
  87.         static timcount = 0;
  88.         
  89.         SEG_LED_Show();                        //数码管刷新的
  90.         
  91.         timcount++;                                //1ms+1
  92.         if( timcount>=10 )                //如果这个变量大于等于10,10ms计数到达
  93.         {
  94.                 timcount = 0;
  95.                 TIM_10MS_Flag = 1;        //10ms时间到了
  96.         }
  97. }
  98. void sys_init()                                //函数定义
  99. {
  100.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  101.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  102.     CKCON = 0; //提高访问XRAM速度
  103.         P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  104.     P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  105.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  106.     P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  107.     P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  108.     P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
  109.     P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
  110.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  111.         
  112.     P3M0 = 0x00;
  113.     P3M1 = 0x00;
  114.    
  115.     P3M0 &= ~0x03;
  116.     P3M1 |= 0x03;
  117.     //设置USB使用的时钟源
  118.     IRC48MCR = 0x80;                            //使能内部48M高速IRC
  119.     while (!(IRC48MCR & 0x01));          //等待时钟稳定
  120.     USBCLK = 0x00;        //使用CDC功能需要使用这两行,HID功能禁用这两行。
  121.     USBCON = 0x90;
  122. }
  123. void delay_ms(u16 ms)        //unsigned int
  124. {
  125.         u16 i;
  126.         do
  127.         {
  128.                 i = MAIN_Fosc/6000;
  129.                 while(--i);
  130.         }while(--ms);
  131. }
复制代码
三、中断优先级的设置
相同优先级,考前的中断源先执行,执行完之后再执行低中断源,且一个中断源在执行的时候不能被打断。
例如:定时器0和P3中断都是最低优先级,定时器0中断号1;P3中断号40,执行完定时器0,再执行P3,之后再执行定时器0。

普通中断-1.png
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:146
  • 最近打卡:2025-07-01 08:48:50

13

主题

165

回帖

441

积分

中级会员

积分
441
发表于 2024-8-25 22:10:06 | 显示全部楼层
chun*** 发表于 2024-7-23 15:47
学习冲哥的《STC32G单片机视频教程》        第八课   蜂鸣器的应用

一、认识蜂鸣器:

看了你的帖子,我感觉我在假学习,实验会做 ,就是写不出你这种帖子
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-7-1 09:54 , Processed in 0.141699 second(s), 98 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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