xiaoxia9623 发表于 2025-2-15 21:06:22

找到了,在 STC 系列单片机中实现自适应时钟的 1 毫秒延时函数,其核心思路是根据单片机的时钟频率来调整定时器的配置,以确保延时时间准确为 1 毫秒。以下为你详细介绍实现步骤并给出示例代码。
实现步骤
确定时钟频率:需要明确 STC 单片机所使用的时钟频率,该频率会影响定时器的定时时间。
选择定时器:通常会选用定时器 0 或者定时器 1 来实现延时功能。
计算定时器初值:依据时钟频率和定时器的工作模式,计算出定时器需要加载的初值,从而实现 1 毫秒的延时。
初始化定时器:对定时器的工作模式、初值等参数进行设置。
启动定时器并等待溢出:启动定时器,等待定时器溢出,以此达到延时的目的。

// 定义系统时钟频率(单位:Hz),这里假设为11.0592MHz
#define SYSCLK 11059200

// 自适应时钟的1毫秒延时函数
void delay_1ms() {
    // 定时器模式寄存器,设置定时器0为模式1(16位定时器)
    TMOD &= 0xF0;// 清除定时器0的模式位
    TMOD |= 0x01;// 设置定时器0为模式1
   
    // 计算定时器初值
    // 定时器计数一次的时间 = 1 / 时钟频率 * 12(12T模式)
    // 1毫秒需要计数的次数 = 1ms / 定时器计数一次的时间
    // 定时器初值 = 65536 - 1毫秒需要计数的次数
    unsigned int timer_initial_value = 65536 - (SYSCLK / 12000);
   
    // 设置定时器0的初值
    TH0 = (unsigned char)(timer_initial_value >> 8);
    TL0 = (unsigned char)timer_initial_value;
   
    // 启动定时器0
    TR0 = 1;
   
    // 等待定时器溢出
    while (!TF0);
   
    // 清除定时器溢出标志
    TF0 = 0;
   
    // 停止定时器0
    TR0 = 0;
}

xiaoxia9623 发表于 2025-2-16 17:35:34

第八集讲的是蜂鸣器,首先讲了蜂鸣器的分类,然后讲到了原理图,再就是结合生活中的产品应用 ,讲到了应用 的场景,这样更能够加深理解,

void Test(void)               
{
        if( KEY1 == 0)               
        {
                delay_ms(10);
                if(KEY1 == 0 )
                {
                        while(KEY1 == 0 );               
                       
               
                        if( Run_Flag==0 )                                               
                        {
                                Run_Flag = 1;                       
                                BEEP = 0;                               
                                delay_ms(10);                       
                                BEEP = 1;                               
                                P40 = 0;                               
                                P6 = 0X00;                               
                                delay_ms(200);                       
                                P6 = 0XFF;                               
                        }
                               
                        else
                        {
                                Run_Flag = 0;
                                BEEP = 0;                               
                                delay_ms(10);                       
                                BEEP = 1;                                       
                                P6 = 0XFF;                                       
                                Run_Mode = 0;                                                       
                        }
                }
        }
       
        if( KEY2 == 0 )
        {
                delay_ms( 10 );
                if( KEY2 == 0 )
                {
                        while( KEY2 == 0);               
                        BEEP = 0;                               
                        delay_ms(10);                       
                        BEEP = 1;                                               
                        Run_Mode ++;                       
                        if( Run_Mode>8 )               
                                Run_Mode = 1;               

                        //P6 =        0XFE;   P6<<1+1
                       
                       
                        P6 = ~(1<< (Run_Mode-1));                //1<<1      0000 0001 -> 1111 1110
                       
                }
        }
}


一步一步的跟着写下来,感觉不一样,印象能深一些。

xiaoxia9623 发表于 2025-2-16 17:41:27

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

其实这个延时函数我更喜欢这样写:
void delay_ms(u16 ms)       
{
        u16 i;
        while(ms--)
        {
                i = MAIN_Fosc/6000;
                while(--i);
        }
}

xiaoxia9623 发表于 2025-2-16 17:47:06

xiaoxia9623 发表于 2025-2-16 17:41
void delay_ms(u16 ms)       
{
        u16 i;


或者是这样写:

void delay_ms(u16 ms)      
{
      u16 j,i;
       for(j=0;j<ms;j++)
      {
                i = MAIN_Fosc/6000;
                while(--i);
      }
}

xiaoxia9623 发表于 2025-2-17 16:17:50

        P70 = 0;                        //

               
                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--;
                        }
                }               
               
        }
}

本课用共阳极数码管显示了0-9的数字,结合按键 实现0-9和9-0的伦流显示,P70等于0打开COM端,然后P6口赋值,显示NUM相对应的数值。一看就会,过两天就会忘掉。一看就会,一写就废。所以说这个东西得经常练习才行,要不然,放下了,也就忘掉了,什么也不会了,必须经常练习。

xiaoxia9623 发表于 2025-2-17 16:21:58

xiaoxia9623 发表于 2025-2-17 16:17
P70 = 0;                        //

               


这种单按键是最简单的按键,一般都是低电平有效,我现在是想学会 电容式感应按键,这种按键在产品中应用最广。最好能做成隔空感应,就更好了,不知道STC的电容式按键,能不能够实现隔空感应?

xiaoxia9623 发表于 2025-2-17 22:58:08

第十集介绍了动态数码管的显示,本图描述了一共4位数码管的轮流显示时——也就是需要延时等待的时间,时间不能低于1毫秒,不管总共有几位数码管,总共的一个轮流显示完毕的时间不能超过20毫秒。如果刷新太慢,也就是如果刷新率太低,频率低于50赫滋,人们会看着一闪一闪的不舒服。动态刷新多们显示跟静态显示的区别在于,需要采用一个数组,来选择打开哪一个位。段码显示内容,位码决定显示在哪一个位上面。位码的显示用到了嵌套数组,这样就可以不按加一的方式显示数组中其它顺序位的内容。{:4_165:}

xiaoxia9623 发表于 2025-2-17 23:02:32

xiaoxia9623 发表于 2025-2-17 22:58
第十集介绍了动态数码管的显示,本图描述了一共4位数码管的轮流显示时——也就是需要延时等待的时间,时间 ...

其实也可以用重新排列段码值的方式,来显示段码的不同的内容的,比如0XC0可以排在第一个位置,也可以排列在第N个位置上面。这样就不需要嵌套数组,但是会看着很乱,其实段码是一个常规的库,一般不建议重新排列的。

xiaoxia9623 发表于 2025-2-18 12:49:46

第十一集讲了定时器,一上来就讲了定时器中断和软件延时的区别。软件不管是delay还是while中的++,一直占用CPU,一但出现程序等待时,++就会停止,这样以来,时间就会增加,就不能准确的定时了,所以这种情况下应该使用定时器,定时器是硬件定时,不受程序等待的影响,定时准确一些,减少了定时的误差避免了定时时间的错误。

xiaoxia9623 发表于 2025-2-18 13:00:09

定时器的应用有的时候是必须的,普通的软件延时是无法完成的,比如让 STC8H 1K 08 定时器 0 在 72 小时的时间后中断,若在这 72小时之内按一下一个键P32,它就取消,从 0 开始。如果不使用定时器,用软件延时的方法,那么程序就什么也不用干了,啥也干不了了呢。


#include <STC8H.H>

sbit Key = P3^2;// 定义按键引脚

unsigned long timer0_count = 0;// 定时器0计数变量
bit timer0_running = 0;// 定时器0运行标志

// 定时器0初始化函数
void Timer0_Init() {
    TMOD &= 0xF0;// 清除定时器0模式位
    TMOD |= 0x01;// 设置定时器0为模式1(16位定时器)
    TL0 = 0x00;// 初值低8位
    TH0 = 0x00;// 初值高8位
    TF0 = 0;// 清除定时器0溢出标志
    ET0 = 1;// 使能定时器0中断
    TR0 = 0;// 停止定时器0
    timer0_count = 0;
    timer0_running = 0;
}

// 中断服务函数
void Timer0_ISR(void) interrupt 1 {
    TL0 = 0x00;// 重装初值低8位
    TH0 = 0x00;// 重装初值高8位
    timer0_count++;
    if (timer0_count >= 72 * 3600 * 1000) {// 72小时(假设1ms中断一次)
      TR0 = 0;// 停止定时器0
      timer0_running = 0;
      // 在这里添加72小时后中断的处理代码
    }
}

// 主函数
void main() {
    Timer0_Init();// 初始化定时器0
    EA = 1;// 使能总中断

    while (1) {
      if (Key == 0) {// 检测按键是否按下
            while (Key == 0);// 等待按键释放
            if (timer0_running) {
                TR0 = 0;// 停止定时器0
                timer0_count = 0;// 清零计数
                TR0 = 1;// 重新启动定时器0
            } else {
                TR0 = 1;// 启动定时器0
                timer0_running = 1;
            }
      }
    }
}

代码说明

1. 变量定义:
-  Key  定义为按键连接的引脚  P3.2 。
-  timer0_count  用于记录定时器0的计数值,以毫秒为单位计算时间。
-  timer0_running  标志位用于表示定时器0是否正在运行。
2. 定时器0初始化函数  Timer0_Init :
- 设置定时器0为模式1(16位定时器)。
- 初始化定时器0的初值为0,清除溢出标志,使能定时器0中断,初始时停止定时器0。
3. 中断服务函数  Timer0_ISR :
- 每次定时器0溢出时,重新加载初值, timer0_count  加1。
- 当  timer0_count  达到72小时对应的毫秒数( 72 * 3600 * 1000 )时,停止定时器0并可在相应位置添加72小时后中断的处理代码。
4. 主函数  main :
- 初始化定时器0并使能总中断。
- 在主循环中,不断检测按键状态。当按键按下并释放后,如果定时器0正在运行,则停止定时器0,清零计数值,然后重新启动定时器0;如果定时器0未运行,则启动定时器0并设置运行标志。
页: 1 [2] 3 4 5 6
查看完整版本: 认真学《32位8051单片机原理及C语言程序设计视频教程》 【免费+包邮送】32G12K128-实