资讯详情

蓝桥杯(单片机开发)训练笔记

各模块电路分析

电源 CH341模块

电路功能:主要为单片机提供电源UART串口调试和下载程序。TENTEN

整个开发板采用双向供电。一路使用DC直接输入5个电源接口V直流电压;一路使用;USB接口输入5V同时,直流电压USB接口是电路串口调试和下载程序的媒介。

CH341芯片的TXD、RXD单片机开发板分别收到15台单片机P30、P31输入输出接口;9号管脚无外部电源.1uF旁路电容(滤波)电容对地起作用;SDA管脚连接到三连排针,下载程序时需要用跳线帽连接(SDA不接地)。

S3作为整个单片机开发板的整体供电开关

矩阵键盘模块

由于比赛中使用的芯片,这里有P37引脚被P44引脚代替,P36引脚被P42引脚代替。

AD转换模块PCF8591

单片机采用两个上拉电阻直接连接的模块IIC通讯,其中AIN二是连接光敏电阻;其中:P20和P21模拟IIC通讯.

AT24C02

单片机采用两个上拉电阻直接连接的模块IIC通讯,其中AIN二是连接光敏电阻;其中:P20和P21模拟IIC通讯.

DS1302时钟模块

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-zOAD1IZI-1658738325439)(assets/20220422_095912_image.png)]

采用SPI协议通讯,P17,P23,P13模拟SPI

超声波测距模块

[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-MLb7fad2-1658738325440)(assets/20220422_100150_image.png)]

使用跳线帽时用跳线帽P10和N_A1连接;P11和N_B1连接;N_AI提供超声波所需的发射脉冲CX20106A从N_B输出与距离成正比的低电平信号,从而达到测距的目的。

单片机IO口拓展

想操作流水灯,数码管段选择,数码管位选择,继电器,蜂鸣器,ULN2003驱动 应结合138和744HC使用02。数字管位段的选择也可以操作8*8点阵.

LM324信号调节电路

NE555N方波产生电路

该板用于产生方波,NET_SIG为输出口;rb3电位器可以调节方波频率.

CT107D流水灯,蜂鸣器

关闭蜂鸣器

拿到板子后肯定会有一些疑问:为什么这个板子上的蜂鸣器总是响,甚至认为是板子的问题; 然而,我们必须养成理性分析问题的习惯。既然蜂鸣器会响,我们就应该分析电路并关闭它:

有源蜂鸣器的正极连接电源VCC,负极利用网络标号“N_BUZZ”连接到ULN2003(高耐压、大电流复合晶体管阵列)OUT引脚,那么ULN2003复合晶体管是什么?具体内部图如下:

通过内部连接图可以看出来,ULN2003内部由7组非门组成,因此当输入端IN输出端为高电平时OUT对于低电平,反之亦然。

在分析完ULN可获得2003芯片的连接和工作原理:N_BUZZ为高电平,蜂鸣器处于关闭状态。因此"OUT7"根据管脚的高电平ULN可以获得2003年的内部原理,IN7管脚为低电平,ULN2007管脚的“IN1~IN七依次连接M74HC573MR存器的“Q1-Q管脚,根据M74HC573MR锁定锁定的工作原理,当VCC以及GND供电无异常,1管脚和11管脚分别连接低电平和高电平,输出为当前芯片输入;但当11管脚为低电平时,M74HC573MR锁存器工作,输出信号为上一个锁定存储的输出电平状态。

也就是说,想操作OUT7.位置或复位P06中间连接了锁存器,打开锁存器的位置Y5C:

电路设计采用74HC138译码器以及74HC02和非门,如下图所示。

当Y5C为1时,WR=0,Y5=0;而WR连接跳线帽GND总是为0让Y5到0就够了。

这里简单列出74HC编写程序提供参考:

关闭蜂鸣器的方法有很多,比如: 1、对P两口进行总线操作,P2|=0xa0; P0&=0xbf;(蜂鸣器引脚复位操作) 或者P2|=0xa0; P0|=0x40;(蜂鸣器引脚的位置操作) 这样就可以开关蜂鸣器了。 2.138译码器(数码管、继电器、蜂鸣器、流水灯、点阵…),所以干脆操作138译码器这三个IO口写成函数。具体代码如下:

void switch_138(unsigned char dat){          switch(dat){                  case 0:P27=0;P26=0;P25=0;break;                  case 1:P27=0;P26=0;P25=1;break;                  case 2:P27=0;P26=1;P25=0;break;                  case 3:P27=0;P26=1;P25=1;break;                  case 4:P27=1;P26=0;P25=0;break;                  case 5:P27=1;P26=0;P25=1;break;                  case 6:P27=1;P26=1;P25=0;break;                  case 7:P27=1;P26=1;P25=1;break;                  //default:break;         } } 

该函数在使用时直接使用switch_138(端口号4-7)P它的优点是增加代码的可读性。

流水灯

为了扩展设计师IO口可谓不择手段,51单片机的典型扩展IO口就是连接8255A,或者这种方法;P控制两口,P0口作为数据传输。 1、对LED操作正确P0口操作,用上面的操作switch_直接选择138(4)U这个锁定器。P0口操作,操作的具体内容要看题目内容。 2.流水灯的操作有时可以看作是一个固定的数组,显示的动画可以通过code 直接牺牲掉ROM换来计算速度;当然也可以用各种循环来判断移位;总之方法很多,没必要一一举例。

基础训练01:LED控制基础

在单片机综合训练平台上实现LED基本控制,首先让奇数LED点亮,然后让偶数LED点亮,然后一切LED闪烁3次,最好一切LED依次点亮,然后依次熄灭,循环往复。

核心:74HC138(三八译码器)HC573(锁定器)HC02(或非门)具体回顾原电路原理分析

参考源码:

#include "reg52.h"    sbit HC138_A = P2^5;   sbit HC138_B = P2^6;   sbit HC138_C = P2^7;    void Delay(unsigned int time) {          while(time--);          while(time--);  } /*======================================================= *功能:通过HC138译码器控制HC573锁存器 *参数:n--HC138译码器低电平引脚          4:Y4输出低电平          5:Y5输出低电平          6:Y6输出低电平          7:Y7输出低电平          8:Y4~Y全部输出高电平 *返回值:无。 =======================================================*/ void Init74HC138(unsigned char n) {         switch(n)         {                 case 4:                         HC138_A = 0;                         HC138_B = 0;                         HC138_C = 1;                         break;                 case 5:                         HC138_A = 1;                         HC138_B = 0;                         HC138_C = 1;                        break;
                case 6:
                        HC138_A = 0;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 7:
                        HC138_A = 1;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 8:
                        HC138_A = 0;
                        HC138_B = 0;
                        HC138_C = 0;
                        break;
        }
}

void LEDRunning()

{
        char i = 0;
        P0 = 0xaa;
        Delay(60000);
        Delay(60000);
        P0 = 0x55;
        Delay(60000);
        Delay(60000);
        for(i = 0; i < 3; i++)
        {
                P0 = 0x00;
                Delay(60000);
                P0 = 0xff;
                Delay(60000);
        }
        for(i = 0; i < 8; i++)
        {
                P0 <<= 1;

                Delay(60000);
        }
        for(i = 0; i < 8; i++)
        {
                P0 <<= 1;
                P0 |= 1;
                Delay(60000);
        }
}

void main()

{
        Init74HC138(4);  
        while(1)
        {
                LEDRunning();  
        }
}

程序优化

HC138通道选择函数

编写HC138函数选择不同的通道优化程序代码,具体的函数如下:

void InitHC138(unsigned char n)
{
  switch(n)
  {
    case 4:
    P2 = (P2 & 0X1f) | 0X80;
    case 5:
    P2 = (P2 & 0X1f) | 0Xa0;
    case 6:
    P2 = (P2 & 0X1f) | 0Xc0;
    case 7:
    P2 = (P2 & 0X1f) | 0Xe0; 
  }
}

P0口输出函数

编写P0输出函数优化程序代码,具体的函数如下:

void OutputP0 (unsigned char channel,unsigned char dat)
{
  InitHC138(channel);
  P0 = dat;
}

共阳数码管的静态显示

数码管的基础知识

要把内容正确的显示在数码管上,首先要明确数码管的类型与段码结构。在CT107D单片机综合实训平台上使用的数码管是 。为什么要看这个型号呢?因为它能告诉你数码管的类型。倒数第2个字母是“ ”,说明这个数码管是 类型的,如果该字母为“ ”则为 类型。不同类型的数据管,其段码数组是截然不同的。

在明确数码管类型之后,就可以确定段码数组了,也就是显示内容所对应的值,例如,要在F3461BH上显示数值“7”,那么就要输出的数值为“0xf8”。怎么样才能得到这个段码数组呢?你可以从网上或其他参考资料上获取,也可以自己对于电路图或者测试段码得到。

在明确数码管类型之后,就可以确定段码数组了,也就是显示内容所对应的值,例如,要在F3461BH上显示数值“7”,那么就要输出的数值为“0xf8”。怎么样才能得到这个段码数组呢?你可以从网上或其他参考资料上获取,也可以自己对于电路图或者测试段码得到。

对于比赛的开发板采用的就是共阳数码管,具体数码管断码表参考如下:

数码管的电路连接

F3461BH是一个4位8段的数码管,其中a、b、c、d、e、f、g、dp引脚分别对应8个段码,该8个引脚通过74HC573锁存器与单片机的P0端口相连。另外有com1~com4四个公共控制脚,该应用为高电平则使能对应位的数码管。两个F3461BH一共有8个com控制引脚,也是通过74HC573锁存器与单片机的P0端口相连的。因此,在操控数码管显示的过程中也离不开74HC138译码器和74HC573锁存器,具体可以参考前面的绍译码器和锁存器的电路原理分析。

共阳数码管的段码表

unsigned char code numtab[18]=
	{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
	0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,
	0xBF,0x7F};//共阳极数码管段码表

静态数码管的位置以及函内容控制函数

void ShowSMG_Bit(unsigned char dat, unsigned pos)//数码管位选控制以及内容控制
{
	InitHC138(6);			//数码管的位置
	P0 = 0x01 << pos;
	InitHC138(7);			//数码管的内容
	P0 = dat;
}

数码管显示函数

void SMG_Static()//数码管显示函数
{
	unsigned char i,j;
	for(i = 0; i < 8; i++)
	{
		for(j = 0; j < 10; j++)//0-9显示
		{
			ShowSMG_Bit(numtab[j],i);
			delay_ms(500);
		}
	}
	for(j = 0; j < 16; j++)//0-9以及A-F显示
	{
		InitHC138(6);			//数码管的位置
		P0 = 0xff;
		InitHC138(7);			//数码管的内容
		P0 = numtab[j];
		delay_ms(500);
	}
}

基础训练02:数码管的静态显示

在单片机综合训练平台上,8个数码管分别单独依次显示0`9值,然后所有的数码管一起同时显示0-F的值,以此往复。

核心:1、数码管的段码和显示数值之间的关系;2、共阳数码管的基本控制方法(com端口与显示码之间的关系)

参考源码:

#include "reg52.h"

unsigned char code SMG_duanma[18]=
		{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
     0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
     0xbf,0x7f};
	 
void Delay(unsigned int t)
{
	while(t--);
	while(t--);
}
			 
void InitHC138(unsigned char n)
{
	switch(n)
	{
		case 4:
			P2 = (P2 & 0x1f) | 0x80;
		break;
		case 5:
			P2 = (P2 & 0x1f) | 0xa0;
		break;
		case 6:
			P2 = (P2 & 0x1f) | 0xc0;
		break;
		case 7:
			P2 = (P2 & 0x1f) | 0xe0;
		break;
	}
}

void ShowSMG_Bit(unsigned char dat, unsigned pos)
{
	InitHC138(6);			//数码管的位置
	P0 = 0x01 << pos;
	InitHC138(7);			//数码管的内容
	P0 = dat;
}

void SMG_Static()
{
	unsigned char i,j;
	for(i = 0; i < 8; i++)
	{
		for(j = 0; j < 10; j++)
		{
			ShowSMG_Bit(SMG_duanma[j],i);
			Delay(60000);
		}
	}
	for(j = 0; j < 16; j++)
	{
		InitHC138(6);			//数码管的位置
		P0 = 0xff;
		InitHC138(7);			//数码管的内容
		P0 = SMG_duanma[j];
		Delay(60000);
		Delay(60000);
	}
}

void main()
{
	while(1)
	{
		SMG_Static();
	}
}

共阳数码管的动态显示

数码管动态显示原理

动态显示实质上就是 。在轮流显示过程中,每位数码管点亮时间为1~2ms,由于人的 及发光二极管的 ,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的I/O端口,而且功耗更低。

HC573得通道选择函数

void SelectHC573(unsigned char channel)
{
	switch(channel)
	{
		case 4:
			P2 =  (P2 & 0x1f) | 0x80;
		break;
		case 5:
			P2 =  (P2 & 0x1f) | 0xa0;
		break;
		case 6:
			P2 =  (P2 & 0x1f) | 0xc0;
		break;
		case 7:
			P2 =  (P2 & 0x1f) | 0xe0;
		break;
	}
}

数码管动态显示控制函数

void DisplaySMG_Bit(unsigned char value, unsigned char pos)
{
	P0 = 0xff;
	SelectHC573(6);
	P0 = 0x01 << pos;
	SelectHC573(7);
	P0 = value;
}

数码管显示函数

void Display_Dynamic()
{
	DisplaySMG_Bit(SMG_duanma[2],0);
	DelaySMG(500);
	DisplaySMG_Bit(SMG_duanma[0],1);
	DelaySMG(500);
	DisplaySMG_Bit(SMG_duanma[1],2);
	DelaySMG(500);
	DisplaySMG_Bit(SMG_duanma[8],3);
	DelaySMG(500);

	DisplaySMG_Bit(SMG_duanma[16],4);
	DelaySMG(500);
	DisplaySMG_Bit(SMG_duanma[16],5);
	DelaySMG(500);

	DisplaySMG_Bit(SMG_duanma[yu/10],6);
	DelaySMG(500);
	DisplaySMG_Bit(SMG_duanma[yu%10],7);
	DelaySMG(500);
}

独立按键的基本操作

一般情况下,独立按键有两个引脚,其中一个通过上拉电阻接到单片机的I/O端口,另外一端接地。也就是说,平时按键没有动作的时候,输出的是高电平,如果有按下动作发生,则输出的是低电平。那么,我们在程序设计的时候,只要扫描跟按键引脚相连的I/O端口,如果发现有低电平产生,则判定该按键处于按下状态。有些时候,电路或者外围有电磁干扰,也会使单片机的I/O端口产生低电平,这种干扰信号会让单片机误认为是按键动作。所以,在扫描按键的时候应该做去抖动处理,把干扰信号过滤掉,从而获得准确的按键状态信号。

延时函数

按键抖动一般是5~10ms,一般按键软件消抖延迟10ms可以

msvoid delay_ms(unsigned char ms)
{
	unsigned int i,j;
	for(i=0;i<ms;i++)
	{
		for(j=0;j<333;j++);
	}
}

独立按键扫描函数

按键S7按下L1点亮,松开熄灭;按键S6按下L2点亮,松开熄灭;

按键S5按下L3点亮,松开熄灭;按键S4按下L4点亮,松开熄灭.

void ScanKeys()
{
	if(S7 == 0)
	{
		delay_ms(10);
		if(S7 == 0)
		{
			L1 = 0;
			while(S7 == 0);
			L1 = 1;
		}
	}
	if(S6 == 0)
	{
		delay_ms(10);
		if(S6 == 0)
		{
			L2 = 0;
			while(S6 == 0);
			L2 = 1;
		}
	}
	if(S5 == 0)
	{
		delay_ms(10);
		if(S5 == 0)
		{
			L3 = 0;
			while(S5 == 0);
			L3 = 1;
		}
	}
	if(S4 == 0)
	{
		delay_ms(10);
		if(S4 == 0)
		{
			L4 = 0;
			while(S4 == 0);
			L4 = 1;
		}
	}
}

矩阵键盘的基本操作

与独立按键不同的是,按键的两个引脚都分别连接的单片机的I/O端口,一个作为行信号,另外一个作为列信号。我们以4X4的矩阵键盘为例,试着探讨其工作方式和扫描思路。

在上面的矩阵键盘中,要识别出黄色按键的按下状态,应该怎么做呢?     对与矩阵键盘,我们只能逐行扫描,然后读取列的状态信号。如果R3行输出低电平,那么黄色按键如果有按下动作的话,那读取C2列信号也应该为低电平,而该行上其他没有按下动作的按键的列信号则为高电平。因此,我们可以得到矩阵键盘的基本扫描步骤:     <1> R1输出低电平,R2、R3、R4输出高电平,逐个读取判断列信号,如果都为高电平则R1行上没有按键按下。     <2> R2输出低电平,R1、R3、R4输出高电平,逐个读取判断列信号。     <3> R3输出低电平,R1、R2、R4输出高电平,发现C2列信号为低电平,那么可以判断得R3行的C2列的按键有按下动作。     <4> R4输出低电平,R1、R3、R4输出高电平,逐个读取判断列信号。     如此循环往复,扫描的按键的状态。     我们知道有按键按下动作,那么又怎么知道是哪一个按键按下呢?这时,我们最好定义一个键值全局变量,给矩阵行列上的每一个的按键编一个唯一的号码。当扫描的某一行某一列的按键动作后,把对应的编号复制给键值变量,这样我们判断这个键值,就知道是那个按键有触发动作了。

矩阵键盘的扫描函数

根据矩阵键盘的扫描原理,矩阵键盘从左到右从上到下,利用数码管依次显示0-F

按键显示函数

void ShowKeyNum(unsigned char value)

{
        InitHC138(6);
        P0 = 0x01;
        InitHC138(7);
        P0 = value;
}

按键扫描函数

void ScanKeys()
{
	R1 = 0;
	R2 = R3 = R4 = 1;
	C1 = C2 = C3 = C4 = 1;
	if(C1 == 0)
	{
		delay_ms(10);
		if(C1 == 0)
		{
			while(C1 == 0);
			key_num = 0;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C2 == 0)
	{
		delay_ms(10);
		if(C2 == 0)
		{
			while(C2 == 0);
			key_num = 1;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C3 == 0)
	{
		delay_ms(10);
		if(C3 == 0)
		{
			while(C3 == 0);
			key_num = 2;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C4 == 0)
	{
		delay_ms(10);
		if(C4 == 0)
		{
			while(C4 == 0);
			key_num = 3;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}

	R2 = 0;
	R1 = R3 = R4 = 1;
	C1 = C2 = C3 = C4 =1;
	if(C1 == 0)
	{
		delay_ms(10);
		if(C1 == 0)
		{
			while(C1 == 0);
			key_num = 4;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C2 == 0)
	{
		delay_ms(10);
		if(C2 == 0)
		{
			while(C2 == 0);
			key_num = 5;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C3 == 0)
	{
		delay_ms(10);
		if(C3 == 0)
		{
			while(C3 == 0);
			key_num = 6;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C4 == 0)
	{
		delay_ms(10);
		if(C4 == 0)
		{
			while(C4 == 0);
			key_num = 7;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}

	R3 = 0;
	R2 = R1 = R4 = 1;
	C1 = C2 = C3 = C4 =1;
	if(C1 == 0)
	{
		delay_ms(10);
		if(C1 == 0)
		{
			while(C1 == 0);
			key_num = 8;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C2 == 0)
	{
		delay_ms(10);
		if(C2 == 0)
		{
			while(C2 == 0);
			key_num = 9;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C3 == 0)
	{
		delay_ms(10);
		if(C3 == 0)
		{
			while(C3 == 0);
			key_num = 10;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C4 == 0)
	{
		delay_ms(10);
		if(C4 == 0)
		{
			while(C4 == 0);
			key_num = 11;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}

	R4 = 0;
	R2 = R3 = R1 = 1;
	C1 = C2 = C3 = C4 =1;
	if(C1 == 0)
	{
		delay_ms(10);
		if(C1 == 0)
		{
			while(C1 == 0);
			key_num = 12;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C2 == 0)
	{
		delay_ms(10);
		if(C2 == 0)
		{
			while(C2 == 0);
			key_num = 13;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C3 == 0)
	{
		delay_ms(10);
		if(C3 == 0)
		{
			while(C3 == 0);
			key_num = 14;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
	else if(C4 == 0)
	{
		delay_ms(10);
		if(C4 == 0)
		{
			while(C4 == 0);
			key_num = 15;
			DisplayKeyNum(SMG_duanma[key_num]);
		}
	}
}

单片机中断系统

什么是中断?

你正在追电视剧《神雕侠侣》,正看得入迷的时候,电话响了,你暂停电视剧,去接电话,在接电话的过程中,门铃又响了,你暂时放下电话,去把门打开。如果追电视剧是在执行主程序,那么电话就是中断源,电话铃响了就是中断请求,暂停电视就是现场保护,接电话就是中断响应,门铃响了是更高一级的中断请求,去把门打开,那就是中断嵌套。开完门回来接着聊电话,那是中断返回,接完电话把电视剧暂停打开就是现场恢复。     内核与外设之间的主要交互方式有两种:轮询和中断。轮询的方式貌似公平,但实际工作效率很低,且不能及时响应紧急事件;中断系统使得内核具备了应对突发事件的能力。     中断有个特点,就是你不知道中断什么时候发生。因此,每个中断都需要有一个中断入口地址,也成为中断向量。这样,不管中断在什么时候发生,它都有一个确定的程序执行起始点。中断响应之后,执行的那段程序,我们称作中断服务函数,也就是这个函数专门是为该中断服务的。

关于中断系统

一般来说,51单片机有5个中断源(忽略定时/计数器2),分2个优先级,这个5个中断源按照自然优先级从高到低依次为:

外部中断0:INT0     定时/计数器0:TF0     外部中断1:INT1     定时/计数器1:TF1         串口中断:RI/TI

下面一图将充分说明51单片机的中断系统结构:

每个中断源都对应着一个固定的入口地址,也就是中断向量,它们依次是:

0    0x0003:  INT0 1    0x000B:  TF0 2    0x0013:  INT1 3    0x001B:  TF1 4    0x0023:  RI/TI

也就是说,不管主程序执行到什么地方,只要外部中断1产生请求,内核要响应该中断,就会到0x0013这个地址去执行代码。如果你是在使用汇编语言进行程序开发的时候,你需要记住每个中断源对应的地址;如果你使用的是C语言,你只需要记住中断源的顺序就可以了,也就是最左边的

中断相关的寄+存器

中断相关的寄存器有4个,每个寄存器都是可以位寻址的,这该编程带来了方便。 其中2个为控制寄存器:IE寄存器与IP寄存器:

中断服务函数程序的编写

一般情况下,中断的处理函数有两个,其一为中断初始化函数,其二为中断服务函数。 初始化函数就是一个普通的函数,而中断服务函数却有特殊的格式要求:     <1> 中断函数没有返回值,也不能带参数。     <2> 函数名后面要跟一个关键字interrupt,说明这是一个中断服务函数。     <3> 在关键字interrupt后面要跟上中断号,说明这个中断服务函数是为那个中断服务的。 中断服务函数的格式为:

void  函数名()  interrupt  中断号
    {  ----函数体----  }

我们要利用定时器0来进行间隔定时,中断程序架构我们C语言可以这样写:

/*=============初始化定时器0===========*/
void Init_Timer0()
{

}
/*=============定时器0中断服务函数===========*/
void Interrupt() interrupt 1
{

}
/*=============主函数===========*/
void main()
{
  Iint_Timer0();
  while(1);
}

定时器的基本原理与应用

什么是定时/计数器?

在没有钟表的时候,定时的方式通过有一注香的时间,或者一桶水的时间。前者烧香不断减少是减法,后者滴水不断增加是加法。     定时/计数器,是一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CPU提出中断处理请求,从而实现定时或者计数功能的外设。定时/计数器的最基本工作原理是 。作为 时,计数信号的来源选择周期性的 ;用作 时,计数信号的来源选择非周期性的 。     

51单片机的定时/计数器

51单片机有两个定时/计数器T0和T1,为16位加法计数器,由低8位TLx和高8位THx两个寄存器组成,最大计数值为65535个计数脉冲。     该加1计数器的计数脉冲来源有2个:     <1> 系统时钟振荡器输出的12分频。     <2> T0或T1引脚输入的外部脉冲信号。      每接收到一个计数脉冲,计数器就会加1,当计数值累计至全为1时(8位255,13位8191,16位65535),再输入一个计数脉冲,计数器便会溢出回零,并且计数器的溢出是TCON寄存器的TF0或TF1位置1,同时向内核提出中断请求。如果定时/计数器工作于定时模式,则表示间隔定时时间到,如果工作与计数模式,则表示计数值已满。      假设单片机的外部晶振为12MHz,那么,经过12分频后输入计数器的计数脉冲为1MHz,即每个脉冲的周期为1us。因此定时器T0的16位工作模式最大的定时时间为65535us,65.5ms。如果要定时10ms的话,计数器就不能够从0开始计数了,必须给它一个计数初值。怎么计算这个初值呢?     要定时10ms,则相当于计数10000个脉冲后计数器的值就到达65535了,那么开始计数的这个地方就是计数初值。     65535 - 10000 = 55535 = 0xd8ef     把这个计算得到的初值写入TH0和TL0寄存器即可:     TH0 = 0xd8;或者 TH0 = (65535 - 10000) / 256;     TL0 = 0xef; 或者  TL0 = (65535 - 10000) % 256;

定时/计数器相关的寄存器

与定时/计数器相关的寄存器除了计数初值寄存器THx和TLx之外,就是TMOD寄存器和TCON寄存器,务必掌握。 <1> TMOD模式控制寄存器,不能进行位寻址,只能字节操作。

<2> TCON中断标志寄存器

定时/计数器的编程思路

在定时/计数器的程序设计中,通常有两个函数:初始化函数和中断服务函数。     在初始化函数中,一般需要进行以下几个配置:     <1> 配置工作模式,即对TMOD寄存器编程。     <2> 计算技术初值,即对THx和TLx寄存器进行赋值。     <3> 使能定时/计数器中断,即ET0或ET1置1。     <4> 打开总中断,即EA =1。     <5> 启动定时器,即TR0或TR1置1。     在中断服务函数中,一般需要进行以下的编程:     <1> 如果不是自动重装模式,需要对THx和TLx重新赋值。     <2> 进行间隔定时到达的逻辑处理(越少越好)。

/**********初始化定时器0***********/
void InitTimer0()
{
	TMOD = 0x01;
	TH0 = (65535 - 50000) / 256;
	TL0 = (65535 - 50000) % 256;

	ET0 = 1;
	EA = 1;
	TR0 = 1;
}

/**********定时器0中断服务函数***********/
void ServiceTimer0() interrupt 1
{
	TH0 = (65535 - 50000) / 256;
	TL0 = (65535 - 50000) % 256;

	count++;
	if(count % 10 == 0)
	{
		L1 = ~L1;
	}
	if(count == 100)
	{
		L8 = ~L8;
		count = 0;
	}
}

串行接口的基本原理与应用

串行接口是一个非常重要的外设,它是单片机与外部终端的数据传输渠道。不管是简单的51单片机,还是复杂的ARM处理器,串口通信都是必不可少的,有些芯片甚至有几个串行接口。就蓝桥杯的“单片机设计与开发”赛项来说,串行通信考查的几率也是相当大的。

串口重要概念概述

<1> 串行通信是指数据一位接一位地顺序发送或接收。     <2> 串行通信有SPI、IIC、UART等多种,最常见最通用的是指UART,无特殊说明,本文指的就是UART。     <3> 串行通信的制式有:单工、半双工、全双工三种。     <4> 计算机的串行通信接口是RS-232的标准接口,而单片机的UART接口则是TTL电平,两者的电气规范不一致,所以要完成两者之间的数据通信,就需要借助接口芯片在两者之间进行电平转换,常用的有MAX232芯片。     <5> 波特率:每秒钟传输的位数,9600波特率就是指每秒钟传输9600位。     注意:在51单片机中需要使用定时器1来产生波特率,因此,如果使用串口通信,则定时器1就不能做其他用途,在初始化串行接口模块的时候,除了要配置SCON寄存器之外,还有根据波特率参数设置定时器1的技术初值。

51单片机的串口相关寄存器

对于传统的51单片机,与串口相关的寄存器有:     TH1和TL1:设置波特率参数。     TMOD:设置定时器1的工作模式。     SBUF:串行通信数据的发送和接收缓冲器。     SCON:串行接口控制寄存器。     在这里主要是掌握SCON,跟串口有关的各种属性都在这个寄存器里进行配置:

如果你在比赛或者应用中使用的是 单片机,你还需要对新增的 进行设置,否则是无法进行串口数据收发的,对于传统的89C52单片机,则不需要这个步骤。

新增的辅助寄存器AUXR的位定义如下:

串口通信的编程思路

在串口通信的程序设计中,主要有串口初始化和数据收发两个部分。     在初始化函数中,基本步骤如下:     <1> 设置定时器1的工作模式,也就是对TMOD寄存器赋值。     <2> 计算波特率参数,并赋值给TH1和TL1寄存器。     <3> 打开定时器1。         如果使用的是STC 12系统单片机,则要设置AUXR寄存器。     <4> 设置SCON寄存器。     <5> 使能串口中断ES。     <6> 使能总中断EA。     数据的发送通常采用查询的方式,而数据的接收则采用中断。     实际上,各个应用程序中,这些代码都差不多,可以参考一下的框架:

标签: 单片机应如何正确驱动继电器250v27000uf出口电容27000uf出口电容二极管250rb二极管u6226p25v电容器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台