327342551 发表于 2023-12-31 16:56:24

本帖最后由 327342551 于 2023-12-31 17:00 编辑

第九集 数码管 静态

- 数码管 就是一堆小灯,每个灯都是一个 位置led

- 正极接一块的是共阳极 尾椎A,负极接一块是共阴极 尾缀K

- 多位的每一位有一个位选的脚

- 使用时候先位选择,然后在确定点哪几个led

- 二进制转成16进制的数字,做成码表

- 段码是哪4个,位码是哪个

- 用key 控制num,num作为表里面的索引使用

327342551 发表于 2023-12-31 17:36:17

本帖最后由 327342551 于 2024-1-2 13:17 编辑

第十集 动态数码管

- 位选+码表来是一个一个点亮

- 一轮次不要多过20ms

- 先选位,位就是共阴阳极,在让段显示对应的图出来

- 刷新率太低就是交替显示

- 使用数组嵌套的方式来实现了键值对。`P6 = SEG_Tab` 这里的Show_tab 是需要显示的内容。里面的内容是 u8 Show_Tab = {1,5,0,0,7,3,3} v这样实际上,P6就变成了 SEG_Tab num++ 北洋嵌套使用了,其实就是键值对的变相应用。必过很聪明

- 开关类型用 bit 定义,然后直接取反就可以

- 通过取余的方法来实现个十百千位的获取

- 因为是固定的可以不用计算,. 一直要显示

327342551 发表于 2023-12-31 19:42:29

第十一集
定时器

- 定时器每隔一段时间完成一个操作,在后台跑,每隔一段出来一下,中断,处理中断再回去

- 定时器还有计数的功能,所以要先选是定时还是计数的功能

- 原理是加法计数

- 12分频是12周期才走一个,不分频精度高,分频的话定时的时间长

- 自动重载,自动到 65536 然后从 0 计数,不自动重载,到了之后需要手动再去,集中模式通过 T0_M1 和 T0_M0 的组合来实现,不可屏蔽中断的优先级最高,做系统常用。

- 启动定时器的条件

- TF0 = 0 (可写可不写)。溢出中断标志
   
- TR0 = 1 必须写。启动定时器,必须开
   
- ET0 = 1 ,启动定时器中断,必须开
   
- EA = 1 总中断,必须开。
   
- 直接按 TMOD 来按组编辑寄存器即可

- 定义中断函数 void Tim0_Isr() interrupt 1

- void Tim0_Isr() 这部分就是个普通的函数名字
   
- interrupt 1 中断号 1,这里需要去查询,不能随便胡写。定时器 0,就是中断号 1.
   
- void Tim0_Isr() interrupt 1 {} 使能中断
   
- void Time0_Init(void) 这部分可以通过 stc-isp 的软件来直接配置。不用自己计算

- 中断的频率越低越好

327342551 发表于 2023-12-31 20:08:09

第十二集 计数器

- T1 pin 用来计数

- 计数器主要用来记录脉冲了多少

- 这个计数到头了,重载。和计时器一样

- TH1 TL1都定义成 0xFF 那么只一次就溢出重载算是个技巧

- 直流电机测速示例

327342551 发表于 2024-1-1 10:22:00

第十三集 简单的程序框架

- 功能做成函数和头文件来使用

- keil 里面添加函数的模板

- extern 变量。可以别的文件中去引用。这个关键字不能定义初值

- static 在函数里面才有用,只有第一次赋值时候才有用。第一次定义是0 的话,后面在遇到就不在赋初值

- 引脚定义写到对应的头文件里面去

- 有else if 先执行else if 之后才去执行 else

- 引脚定义、变量声明、函数声明

- if else按键检测

- u8 KE_ReadState(u8 keynum) 这个定义的是一个有返回值的函数,返回值的类型 u8

- 状态机可以出写成switch case的样子,比ifelse 更好

- 状态机是过多长时间采取执行一次,刷新状态

- 其他的程序去取状态就好了

- 定时器比 delay 好多了

- 做 ++ 运算的临时的变量,最后都要重置一下

327342551 发表于 2024-1-1 10:54:44

第十四集 矩阵按键

- 行列的形式来了看具体哪个key按下,4+4 行高电平,列低电平。行低电平列高电平。按了那个去读取就好了

- 位运算,非常的有用,可以减少非常多的判断让程序更快

- 加一个old的状态值,来判断

- switch case 有一个default 都不满足的时候执行的语句

- 每行一个注释,十分有必要

- c语言可以,a = b = c = d = 1;同时赋值

327342551 发表于 2024-1-1 11:15:56

第十五集 外部中断

- 中断就是到了这就到中断里面去执行,完了再出来

- 中断有优先级,已经在低优先级的中断里面执行了,有高优先级的,这时候要到高优先级里面去,高优先级完事,再回到低优先级里面

- 部分优先级可以用软件设置
   
- 中断的开关

- 总开关 EA = 1
   
- 每个中断也都有自己的开关
   
- 每个单片机有哪些去查表,查完再用

- 次数最小,优先级最高

- 外部中断是引脚上电平变化进入中断

- 只能用固定的脚,看图
   
- 看中断结构图,非常有用,看怎们用中断

- 定义的东西注释一定要清晰,否则错了不好看出来

- 及时响应的用外部中断来实现

327342551 发表于 2024-1-2 10:47:11

stc89c52 定时器头文件改造
这里千万不要使用stc-isp里面的自带的计算器,auxr寄存器功能不一样的,也没有1T的只有12T和6T
头文件使用的stc-isp里面生成的sdcc的库,我的环境为 vscode +sdcc



#ifndef __TIM0_H
#define __TIM0_H
#include <../inc/stc89c5xrc.h>

//------------------------------函数声明------------------------------
void Timer0_Init(void);                        //1毫秒@12.000MHz

#endif





#include "./TIM/tim0.h"


//========================================================================
// 函数名称: Timer0_Init
// 函数功能: 定时器0初始化
// 入口参数: 无
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2024
// 当前作者:
// 其他备注:
//========================================================================

// 我需要的是定时器0 模式1 16位 定时器

// 公式:(2^16– X)× 12 ÷ 晶振频率 = 定时时间(默认单位us)
// —————————————————————————————————
// X是未知量
// —————————————————————————————————
// 16是根据方式选择的,可以自行选择,方式1为16位
// 方式0 :13 (少用)
// 方式1 :16 (最常用)
// 方式2 :8 (常用)
// 在线计算
// TH0 时间/256
// TL0 时间%256


void Timer0_Init(void)                //1毫秒@12.000MHz
{
        // AUXR &= 0x7F;                        //定时器时钟12T模式
        // TMOD &= 0xF0;                        //设置定时器模式
        // 以上2句在89c52上不好使 可能软件太老了,

        TMOD = 0x01;                        //设置定时器模式 0000 gate00001 模式 16 位

        TL0 =64536%256;                                //设置定时初始值
        TH0 = 64536/256;                        //设置定时初始值

        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}



/*                //复制这个文件的时候,记得把这个终端还函数复制到主程序里
void Timer0_Isr(void) interrupt 1
{
       
}
*/

327342551 发表于 2024-1-5 08:49:08

按键扫描 stc89c52
大体基于教学视频修改
#ifndef __KEY_H
#define __KEY_H
#define u8 unsigned char
#define u16 unsigned int

#include <../inc/stc89c52.h>

//------------------------------引脚定义------------------------------
#define KEY         P3                              //P30-P33 目前可用
                              // 依次定义是key1-key4 p30-P33
#define KEY1      0                              //按键1
#define KEY2      1                              //按键2
#define KEY3      2                              //按键3
#define KEY4      3                              //按键4

//------------------------------变量声明------------------------------
#define      KEY_NOPRESS                0                //按键未按下
#define      KEY_FILCKER                1                //消抖
#define      KEY_PRESS                2                //单击
#define      KEY_PRESSOVER      3                //单击结束
#define      KEY_LONGPRESS      4                //长按3秒
#define      KEY_LONGOVER      5                //长按结束
#define      KEY_RELAX                6                //按键松开


//------------------------------函数声明------------------------------
void KEY_Deal(void);                        //检查所有的按键状态
u8 KEY_ReadState(u8 keynum);      //读取指定的按键的状态

#endif



#include "../KEY/key.h"

u16 Count = {0,0,0,0};               // 数组里记录了每一个按键按下的次数
u8LastState = 0;                                                //8位变量         b0=1,代表k0上一次按下过

//========================================================================
// 函数名称: KEY_Deal
// 函数功能: 按键状态读取
// 入口参数: 无
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2024 - 1-2
// 当前作者:
// 其他备注:循环读取四个端口的状态,并将按下的时间赋值给 Count 数组,按下的状态赋值给LastState
//========================================================================
void KEY_Deal(void)                        //检查所有的按键状态 10ms执行一次
{
      u8 i = 0;
      for(i=0;i<4;i++)                                        //循环4次 i的取值范围是0-4代表了P30-P33的状态查询
      {
                if( ~KEY & ( 1<<i ) )                        //持续按下,变量+1,没按是1111 1111 0xFF 按下p30是 1111 1110,取反之后是 0000 0001。i=0, 0x00 左移1位是0x01,0的左移只能是1。最后0x01和0x01做与运算。对上了就+1
                // 左移符号是 <<,它表示将一个二进制数向左移动指定的位数。例如,1 << 2 表示将二进制数 1 向左移动 2 位,即在二进制数的末尾添加两个 0,得到二进制数 100。左移符号的作用是将一个数乘以 2 的指定次幂。
                {
                        if( Count<6000 )      //u16 最大值65535 不能一直加下去
                              Count ++;                        //按键按下,这个计数变量+1
                }
                else                                                      //按键松开了,变量清0
                {
                        if( Count>0 )                        //如果这个变量是按下过的
                        {
                              LastState |= (1<<i);      //这个变量相应的标志位置位,把8个标志位按0-4,依次赋值1
                        }
                        else
                        {
                              LastState &= ~(1<<i);      //这个变量相应的标志位清0,清零单一的标志位
                        }
                        Count = 0;                              //按键按下,这个计数变量清0
                }
      }
}

//========================================================================
// 函数名称: KEY_ReadState
// 函数功能: 读取指定的按钮的状态
// 入口参数: @keynum : 按钮的端口号 例如P32端口,端口号就是2
// 函数返回: 看其他备注
// 当前版本: VER1.0
// 修改日期: 2023 - 1- 1
// 当前作者:
// 其他备注: 函数返回值如下
      #define      KEY_NOPRESS                0                //按键未按下
      #define      KEY_FILCKER                1                //消抖
      #define      KEY_PRESS                2                //单击
      #define      KEY_PRESSOVER      3                //单击结束
      #define      KEY_LONGPRESS      4                //长按3秒
      #define      KEY_LONGOVER      5                //长按结束
      #define      KEY_RELAX                6                //按键松开
//========================================================================

//               10ms检测一次
//               高电平         低电平
// 状态 没按下                     <30ms   消抖
//               松开            ==30ms   单击
//                                             <3000ms单击结束
//                                             ==3000ms长按
//                                                 >3000ms   长按结束
// 总时间计数不超过6000ms,一直加就没头了,还有就是要考虑数据类型 u16的最大是65536




// 下面的keynum 是key1-KEY4 也就是0-3在头文件里面定义的
u8 KEY_ReadState(u8 keynum)      //读取指定的按键的状态 10ms执行一次
{
      if( Count>0 )                                        //按键是按下的各种状态返回,用的最上面的数组
      {
                if( Count<3 )                              //按下<30ms 返回消抖状态
                {
                        return KEY_FILCKER;
                }
                else if( Count==3 )                        //按下正好30ms 返回单击
                {
                        return KEY_PRESS;
                }
                else if( Count<300 )                //按下不到3000ms 返回单击结束
                {
                        return KEY_PRESSOVER;
                }               
                else if( Count==300 )                //按下正好3000ms 返回长按状态
                {
                        return KEY_LONGPRESS;
                }
                else                                                                //长按结束
                {
                        return KEY_LONGOVER;
                }                        
               
      }
      else                                                                        //按键已经松开了,返回各种状态
      {
                if( LastState &( 1<<keynum ) )                //按键之前按下过
                {
                        return KEY_RELAX;               
                }
                else                                                                //按键之前没有按下
                {
                        return KEY_NOPRESS;
                }
      }
}


327342551 发表于 2024-1-5 08:51:07

stc89c52结合sdcc和stc-isp里面的头文件做的头文件

#ifndef __STC89C52_H__
#define __STC89C52_H__

/////////////////////////////////////////////////
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long





/* redefine some keywords */

// primitive type
typedef __sfr sfr;
typedef __sfr16 sfr16;
typedef __sfr32 sfr32;
typedef __sbit sbit;
typedef __bit bit;

// keywords
#define interrupt __interrupt
#define using __using
#define _at_ __at
#define _priority_
#define _task_

// storage type
#define reentrant __reentrant
#define compact
#define small __near
#define large __far
#define data __data
#define bdata
#define idata __idata
#define pdata __pdata
#define xdata __xdata
#define code __code


//包含本头文件后,不用另外再包含"REG51.H"

__sfr       __at(0x80)      P0;
    __sbit__at(0x80)      P00;
    __sbit__at(0x81)      P01;
    __sbit__at(0x82)      P02;
    __sbit__at(0x83)      P03;
    __sbit__at(0x84)      P04;
    __sbit__at(0x85)      P05;
    __sbit__at(0x86)      P06;
    __sbit__at(0x87)      P07;

__sfr       __at(0x81)      SP;
__sfr       __at(0x82)      DPL;
__sfr       __at(0x83)      DPH;
__sfr       __at(0x87)      PCON;

__sfr       __at(0x88)      TCON;
    __sbit__at(0x8F)      TF1;
    __sbit__at(0x8E)      TR1;
    __sbit__at(0x8D)      TF0;
    __sbit__at(0x8C)      TR0;
    __sbit__at(0x8B)      IE1;
    __sbit__at(0x8A)      IT1;
    __sbit__at(0x89)      IE0;
    __sbit__at(0x88)      IT0;

__sfr       __at(0x89)      TMOD;
__sfr       __at(0x8A)      TL0;
__sfr       __at(0x8B)      TL1;
__sfr       __at(0x8C)      TH0;
__sfr       __at(0x8D)      TH1;
__sfr       __at(0x8E)      AUXR;

__sfr       __at(0x90)      P1;
    __sbit__at(0x90)      P10;
    __sbit__at(0x91)      P11;
    __sbit__at(0x92)      P12;
    __sbit__at(0x93)      P13;
    __sbit__at(0x94)      P14;
    __sbit__at(0x95)      P15;
    __sbit__at(0x96)      P16;
    __sbit__at(0x97)      P17;
   
    __sbit__at(0x91)      T2EX;
    __sbit__at(0x90)      T2;

__sfr       __at(0x98)      SCON;
    __sbit__at(0x9F)      SM0;
    __sbit__at(0x9E)      SM1;
    __sbit__at(0x9D)      SM2;
    __sbit__at(0x9C)      REN;
    __sbit__at(0x9B)      TB8;
    __sbit__at(0x9A)      RB8;
    __sbit__at(0x99)      TI;
    __sbit__at(0x98)      RI;

__sfr       __at(0x99)      SBUF;

__sfr       __at(0xA0)      P2;
    __sbit__at(0xA0)      P20;
    __sbit__at(0xA1)      P21;
    __sbit__at(0xA2)      P22;
    __sbit__at(0xA3)      P23;
    __sbit__at(0xA4)      P24;
    __sbit__at(0xA5)      P25;
    __sbit__at(0xA6)      P26;
    __sbit__at(0xA7)      P27;
   
__sfr       __at(0xA2)      AUXR1;

__sfr       __at(0xA8)      IE;
    __sbit__at(0xAF)      EA;
    __sbit__at(0xAE)      EC;
    __sbit__at(0xAD)      ET2;
    __sbit__at(0xAC)      ES;
    __sbit__at(0xAB)      ET1;
    __sbit__at(0xAA)      EX1;
    __sbit__at(0xA9)      ET0;
    __sbit__at(0xA8)      EX0;
   
__sfr       __at(0xA9)      SADDR;

__sfr       __at(0xB0)      P3;
    __sbit__at(0xB0)      P30;
    __sbit__at(0xB1)      P31;
    __sbit__at(0xB2)      P32;
    __sbit__at(0xB3)      P33;
    __sbit__at(0xB4)      P34;
    __sbit__at(0xB5)      P35;
    __sbit__at(0xB6)      P36;
    __sbit__at(0xB7)      P37;

    __sbit__at(0xB7)      RD;
    __sbit__at(0xB6)      WR;
    __sbit__at(0xB5)      T1;
    __sbit__at(0xB4)      T0;
    __sbit__at(0xB3)      INT1;
    __sbit__at(0xB2)      INT0;
    __sbit__at(0xB1)      TXD;
    __sbit__at(0xB0)      RXD;

__sfr       __at(0xB7)      IPH;
__sfr       __at(0xB8)      IP;
    __sbit__at(0xBD)      PT2;
    __sbit__at(0xBC)      PS;
    __sbit__at(0xBB)      PT1;
    __sbit__at(0xBA)      PX1;
    __sbit__at(0xB9)      PT0;
    __sbit__at(0xB8)      PX0;

__sfr       __at(0xB9)      SADEN;
   
__sfr       __at(0xC0)      XICON;
    __sbit__at(0xC7)      PX3;
    __sbit__at(0xC6)      EX3;
    __sbit__at(0xC5)      IE3;
    __sbit__at(0xC4)      IT3;
    __sbit__at(0xC3)      PX2;
    __sbit__at(0xC2)      EX2;
    __sbit__at(0xC1)      IE2;
    __sbit__at(0xC0)      IT2;

__sfr       __at(0xC8)      T2CON;
    __sbit__at(0xCF)      TF2;
    __sbit__at(0xCE)      EXF2;
    __sbit__at(0xCD)      RCLK;
    __sbit__at(0xCC)      TCLK;
    __sbit__at(0xCB)      EXEN2;
    __sbit__at(0xCA)      TR2;
    __sbit__at(0xC9)      C_T2;
    __sbit__at(0xC8)      CP_RL2;
   
__sfr       __at(0xC9)      T2MOD;
__sfr       __at(0xCA)      RCAP2L;
__sfr       __at(0xCB)      RCAP2H;
__sfr       __at(0xCC)      TL2;
__sfr       __at(0xCD)      TH2;

__sfr       __at(0xD0)      PSW;
    __sbit__at(0xD7)      CY;
    __sbit__at(0xD6)      AC;
    __sbit__at(0xD5)      F0;
    __sbit__at(0xD4)      RS1;
    __sbit__at(0xD3)      RS0;
    __sbit__at(0xD2)      OV;
    __sbit__at(0xD1)      F1;
    __sbit__at(0xD0)      P;

__sfr       __at(0xE0)      ACC;

__sfr       __at(0xE1)      WDT_CONTR;
__sfr       __at(0xE2)      ISP_DATA;
__sfr       __at(0xE3)      ISP_ADDRH;
__sfr       __at(0xE4)      ISP_ADDRL;
__sfr       __at(0xE5)      ISP_CMD;
__sfr       __at(0xE6)      ISP_TRIG;
__sfr       __at(0xE7)      ISP_CONTR;

__sfr       __at(0xE8)      P4;
    __sbit__at(0xE8)      P40;
    __sbit__at(0xE9)      P41;
    __sbit__at(0xEA)      P42;
    __sbit__at(0xEB)      P43;
    __sbit__at(0xEC)      P44;
    __sbit__at(0xED)      P45;
    __sbit__at(0xEE)      P46;
    __sbit__at(0xEF)      P47;

__sfr       __at(0xF0)      B;

/////////////////////////////////////////////////

#endif

页: 1 [2] 3
查看完整版本: 学习心得STC32位8051单片机原理及C语言程序设计视频教程