M20 中断、定时器与程序存储方式

发布者:幸福旅程最新更新时间:2023-01-30 来源: zhihu关键字:M20  中断  定时器  程序  存储方式 手机看文章 扫描二维码
随时随地手机看文章

void main() //主程序 不同单片机写法基本一致
{
}

interrupt() //不同单片机 中断程序写法不同
{
}


  • 多个中断类似于多个中断车道的车行进,如果都来抢占红色小车的主车道,会造成红车行进缓慢。

  • 所以中断程序写最简短的代码,尽量少的占用主车道的时间。


以上提到了四个关键名词:

  • 中断

  • 定时器

  • 主程序

  • 中断程序

书籍会给一个名词简短一两句话,作为解释或者定义,实际上大部分名词很难用一句话说明。很多同学学习过程中感觉越学越困难,越来越看不懂,实际上,关键问题就是很多名词需要一本书1000页打底的书来解释才行,我们把自己限定到仅看课本或者一两本关联度很少的书,这样自然是越学越累。因为这些关键名词都没有理解,他们又是后续章节的基础,后续的故事...

继续说这四个名词,

中断是一种机制,为了实现:

  • 提升时间利用率

  • 快速响应信号

  • 尝试一心二用、一心三用

我喜欢单片机比作一个人。

以人的行为来理解中断,我们看一本小说或者看一个电影,看小说的过程中,拿起手机来接了个电话,电话接完了,接着又看小说剩下的内容,过了一会口渴了,又去喝了杯水,接着再看..

  • 看小说是大脑主程序在运行

  • 接电话 大脑切换到电话中断程序

  • 喝水 大脑切换到喝水中断程序

空间和时间是永恒的主题!


从时间上理解中断:

从空间上理解中断:

程序要存储在两个主要的地方

A、电脑中,我们编写的程序源代码(主程序和中断程序都存储在main.c中)


B、编译完成形成二进制代码下载到单片机的程序存储器中(ProgramFlash)



a、首先我们要找到中断程序的位置(以stc单片机为例,其他51单片机类似)

b、看看程序存储器大小

c、写了一段定时器0的中断小程序,我们依照这个程序继续往下分析

源码下载在这里:

向导团队/step by step study singlechip

目录:step-by-step-study-singlechipstepbysteptimertimer0keil

本程序实现功能

  • 启用定时器0

  • 1ms定时并开启定时器中断

  • 1ms定时到达开始计数,计数1000次 LED灯状态反转

  • 主循环空转

  • 主要运行函数为定时器初始化函数和中断函数

#include "reg51.h" //引用头文件


//以下两个类型转换语句只是为了用短单词替代两个单词,写程序时方便

typedef unsigned char BYTE; //BYTE 代替 unsinged char 代表一个字节长度

typedef unsigned int WORD; //WORD 代替 unsigned int  代表两个字节(一个字)长度



//-----------------------------------------------


/* define constants */

#define FOSC 11059200L //主晶振宏定义


#define T1MS (65536-FOSC/12/1000) //1ms timer calculation method in 12T mode //宏定义 1ms定时器在12T模式下的计算方法


/* define SFR */

sbit TEST_LED = P1^0; //work LED, flash once per second //工作LED 1秒闪烁1次


/* define variables */

WORD count; //1000 times counter //1000毫秒计数器


unsigned char runCode; //运行代码 主要函数和关键语句添加,通过观察此变量了解程序运行到的位置


//-----------------------------------------------


/* Timer0 interrupt routine */


void tm0_isr() interrupt 1

{

    runCode=5;


    TL0 = T1MS; //reload timer0 low byte //重新装入定时器0低字节

    TH0 = T1MS >> 8; //reload timer0 high byte //重新装入定时器0高字节

    if (count-- == 0) //1ms * 1000 -> 1s //1ms定时计数1000次 后是1秒

    {

        runCode=6;

        count = 1000; //reset counter //复位计数器

        TEST_LED = ! TEST_LED; //work LED flash //LED灯闪烁

    }

}



void init_timer0()

{

    runCode=3;


    TMOD = 0x01; //set timer0 as mode1 (16-bit) //设置定时器0 16bit工作模式

    TL0 = T1MS; //initial timer0 low byte //初始化定时器0 低字节

    TH0 = T1MS >> 8; //initial timer0 high byte //初始化定时器0 高字节

    TR0 = 1; //timer0 start running //启动定时器0

    ET0 = 1; //enable timer0 interrupt //开启定时器0中断

    EA = 1; //open global interrupt switch //打开所有中断

    count = 0; //initial counter //初始化计数器

}


/* main program 主程序*/

void main()

{

    runCode=1;

    init_timer0(); //初始化定时器函数



    while (1) //主循环

    {

        runCode=2;

        ; //分号代表空转,不做任何事情,但是;也会占用单片机运行时间

    } //loop

}

中断函数很特殊是被keil内部程序调用的,它与主函数(main)是一个等级,不能被主函数直接调用,其他函数可以被主函数调用。

e、继续往下进行,我们只在keil中编写完了程序还不行,需要知道程序是怎么一步步编译成单片机能够存储的格式的。

  • 源程序编写完成

  • 编译链接成二级制格式文件

我们从C语言源文件很难看出中断程序最终存储在那个位置,keil有个强大的功能是可以直接变成汇编语言查看。汇编语言更接近机器语言,从里面我们就能够找到程序的具体位置。

先进行几步设置

1)keil 设置为内部仿真模式

2)点击调试按钮

3)打开汇编语言窗口 打开存储器窗口

4)我们观察下中断程序 C语言 汇编语言格式和存储代码对应的空间

5)理解一个概念 单片机程序存储空间就是用硅晶体组成的一个个电路,也就是一组组开关。然后集成在单片机里面。回头看这张图

0000H~3FFFH 把main.c 内部的程序代码都装进去了,只是变成了单片机认识的二进制的0,1,再进一步实际上是把单片机内部的一个个开关打开还是关上了,1关闭,0开启。

我们看4)中存储器是16进制数 16进制能够一一对应二进制数,例如十六进制FF=11111111

从下图我们可以看出程序就是从哪里执行,运行中从那个地址再调用函数... 所有的代码无论开始的格式是什么样的,最终都变成二进制0、1。(16进制作为中间过程)

6)我们洋洋洒洒写了很多程序代码,实际编译完成写入单片机是很短的代码

f、现在我们再看程序是怎么从C编译成二进制01的就容易理解了


g、重新编译生成hex文件,可用于proteus仿真或烧写单片机

h、最终调试观察运行结果




通过学习,我们知道中断程序(中断函数)和主程序都存储在单片机程序存储器中,通过代码的相互调用反复执行。

先在定时器寄存器中放置一个值 当这个值累加到超过寄存器能存储的最大数就触发中断,累加1实际上会消耗一定的时间,累加到特定数值就可以判断出总时间1ms,本程序64614为初始值,

#define FOSC 11059200L //主晶振宏定义

#define T1MS (65536-FOSC/12/1000)

11059200÷10÷1000=921.6 65536-921.6=64614.4 =FC66(16进制)

所以定时器寄存器要存FC66, FC66不断+1 直到等于65536(0x10000)超出了定时器的计数范围(16位定时器只能存FFFF也就是65535)1ms时间到。


关键字:M20  中断  定时器  程序  存储方式 引用地址:M20 中断、定时器与程序存储方式

上一篇:1、换种思路学Proteus之新建工程并点亮一颗LED灯
下一篇:最简洁的单片机状态机模型(X-状态机)

推荐阅读最新更新时间:2024-10-27 16:25

M20 中断定时器程序存储方式
void main() //主程序 不同单片机写法基本一致 { } interrupt() //不同单片机 中断程序写法不同 { } 多个中断类似于多个中断车道的车行进,如果都来抢占红色小车的主车道,会造成红车行进缓慢。 所以中断程序写最简短的代码,尽量少的占用主车道的时间。 以上提到了四个关键名词: 中断 定时器 主程序 中断程序 书籍会给一个名词简短一两句话,作为解释或者定义,实际上大部分名词很难用一句话说明。很多同学学习过程中感觉越学越困难,越来越看不懂,实际上,关键问题就是很多名词需要一本书1000页打底的书来解释才行,我们把自己限定到仅看课本或者一两本关联度很少的书,这样自然是越学越累。因为这
[单片机]
cc2530裸机编程系列笔记2--定时器Timer1模模式程序 中断方式
上篇专题中描述的是采用查询的方式完成定时器Timer1模模式程序的设计,本篇则介绍采用中断的方式完成定时器Timer1模模式程序的设计。查询的方式,上篇已经介绍过就是在主程序中不断的查询中断标志是否被置位,置位后则进行相应处理。中断的方式则为,当中断产生时,CC2530在硬件的作用下将程序跳转到中断中断服务程序去执行。先贴出中断方式的程序: #include ioCC2530.h #define uint8 unsigned char #define uint16 unsigned int #define BIT(x) (1 x) #define LED1 P1_0 /**********************
[单片机]
数码管动态显示+定时器中断方式+Protues
1 仿真现象 2 程序设计 2.1 主程序 #include DisplaySmg.h #include Timer0.h sbit LED = P1^0; unsigned int SystemTimer=0; //系统时间 unsigned char SystemFlag=1; //初始状态 unsigned int NUM = 1983; //待显示数据 void disp_num(); void main() { Timer0Init(); //启动定时器T0 do //开机显示 { if(SystemTi
[单片机]
数码管动态显示+<font color='red'>定时器</font><font color='red'>中断</font><font color='red'>方式</font>+Protues
数码管动态显示(定时器中断方式)+小数点+高位为0不显示
1 仿真现象 2 程序设计 2.1 主程序 #include REG52.H #include DisplaySmg.h #include Timer0.h unsigned int adc_result = 1234; void disp_num(void) //显示四位十进制数 { if(adc_result =1000) //千位 { LedBuf = adc_result/1000; } else { LedBuf =23; //不显示 } if(adc_result =100)
[单片机]
数码管动态显示(<font color='red'>定时器</font><font color='red'>中断</font><font color='red'>方式</font>)+小数点+高位为0不显示
STM32CUBEMX(8)--USART通过定时器中断方式接收不定长数据
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接收的数据打印出去。 DMA接收请查看:https://blog.csdn.net/qq_24312945/article/details/106557538 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板: 选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示: 配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示: 配置时钟树 STM32F0的最高主频到48M,所以配置48即可: 串口配置 本次实验使用的串口1进行
[单片机]
STM32CUBEMX(8)--USART通过<font color='red'>定时器</font><font color='red'>中断</font><font color='red'>方式</font>接收不定长数据
STM32单片机使用定时器中断方式实现毫秒级延时的设计
因为STM32 HAL库中仅有对HAl_Delay()毫秒级的延时,为实现精确的微秒级延时,就不得不修改Systick,但由于HAL库内部使用其作为超时判断等操作,对其修改会发生不可预期的错误,不建议修改。因此,使用通用定时器进行定时操作。 参考网上例程,使用定时器中断方式实现延时,代码如下: TIM3溢出时间=72MHz/(71+1)/(0+1)=1Mhz=1us 计数模式:向上计数模式 使能TIM3中断 */ __IO static uint32_t usDelay=0; void Delayms(uint32_t ms) { Delayus(ms*1000); } void Delayus(uint32_t us) {
[单片机]
STM32单片机使用<font color='red'>定时器</font><font color='red'>中断</font><font color='red'>方式</font>实现毫秒级延时的设计
ARM LPC2103定时器中断方式寄存器设置
定时器查询方式定时器初始化: 1、设置定时器分频数,为(x+1)分频 2、匹配通道X中断并复位TxTC 3、比较值(1S定时值) 4、启动并复位TxTC 如: T1PR = 99; // 设置定时器0分频为100分频,得110592Hz T1MCR = 0x03; // 匹配通道0匹配中断并复位T0TC T1MR0 = 110592/2; // 比较值(1S定时值) T1TCR = 0x03; // 启动并复位T0TC T1TCR = 0x01; 研究了好长一段时间,LPC210X的定时器,查询方式定时很简单如上面,但中断方式要操作好多寄存器,太麻烦,一直是一头雾水。好不容易理出了思路,现将一段例程粘贴备忘。 #include
[单片机]
定时器计数 数码管显示0到99 (中断和查询两种方式
定时器中断方式计数 #include reg51.h #define uchar unsigned char #define uint unsigned int uchar tab ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, 0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E}; uchar data_L, data_H; uchar data_0, b; void delay(uchar time) { uchar m; for(m=0;m time;m++) ; } void T0_init() { TMOD = 0x
[单片机]
<font color='red'>定时器</font>计数 数码管显示0到99 (<font color='red'>中断</font>和查询两种<font color='red'>方式</font>)
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved