目录

基本外设

1.1锁存器,led灯,蜂鸣器,继电器及注意事项

1.2 数码管(板载共集成8位共阳级数码管),数码管分段选和位选

1.3 矩阵键盘和独立键盘

1.4 数码管消影:

1.5 按键的长按和短按(嵌套if实现)

1.6  按键的长按和短按(状态机实现)

常用外设

2.1 DS18B20温度传感器

2.2 串口

2.3 超声波:

2.4 iic总线

2.5 NE555频率测量

2.6 DS1302实时时钟

2.7  PWM的控制



基本外设

1.1锁存器,led灯,蜂鸣器,继电器及注意事项

 单片机竞赛(蓝桥杯电子类)用的开发板的芯片是stc15f2k60s2,我第一次拿到这板子的时候,发现和其他我之前买的最小开发板最大的不同是它有锁存器,共有4个(Y4,Y5,Y6,Y7),锁存器(单片机板子上的锁存器由若干个D触发器组成)的作用是保持之前输入信号的状态!

-- Y4锁存器控制led灯,P0输入低 电平点亮,输入高电平熄灭

-- 蜂鸣器低电平响,高电由于ULN2003反相器  的 存 在,输入为低电平灭,高电平响。

--- 继电器,输入低电平不工作,高电平工作

由上可知  Y5锁存器控制蜂鸣器 继电器等 ,ULN2003相当于一个反相器

而输入信号Y4C.Y5C,Y6C,Y7C则由以下或非门(实际就相当于非门)输出得到,而Y4,Y5,Y6,Y7则由74138译码器得到

P2的高三位控制,所以

                        Y4:P2=P2&0x1f|0x80;

                        Y5:P2=P2&0x1f|0xa0;

                        Y6:P2=P2&0x1f|0xc0;

                        Y7:P2=P2&0x1f|0xe0;

为什么这样写:以Y4为例,P2&0x1f把高三位置为0,再位或0x80,则把高三位赋值为100,
对于的译码器即为Y4',次数Y4'输出为0有效,而自始至终其他位都未变,
实际上这个单片机只用了板载的外设,P2除高三位外,其他位都没用,大家直接赋值0x80也没问题。

简单的说,锁存器就是一个大门,锁存器打开, 这时控制P0的电位变化,信号则被送进去,锁存器关闭,外界P0无论信号怎么变,一般来说只要该外设锁存器未打开,都不会对此外产生影响。

注意:单片机电位变化只有高低两种电平,而单片机板子上的LED灯,蜂鸣器,数码管段选和位选都是P0口控制 ,这时候大家就知道锁存器的作用了,没错,P0总不可能同时精确的控制多个外设若是设计不加锁存器,则很容易出现控制不准确,而加了锁存器后,相应的外设就对应了多个锁存器,要控制那个外设先初始化锁存器的状态和P0口的状态,然后再给P0赋值,再开对应外设的锁存器,然后再关闭锁存器。

比如点个灯:

//比如点个灯P0=0x00;//先开P0,0有效,即为全部点亮
P2=(P2&0x1f)|0x80;
P2=P2&0x0f;
/*
P2&0x1f把高三位置为0,再位或0x80,则把高三位赋值为100,
对于的译码器即为Y4',次数Y4'输出为0有效,而自始至终其他位都未变,
实际上单片机只用了板载的外设,P2除高三位外,其他位都没用,大家直接赋值0x80也没问题
*///注意:为什么要先初始化P0,如果要打开锁存器的话,P0的状态就直接输入进去了,可能会存
//在的控制不准确,这在后面多次操作数码管或是蜂鸣器更为明显

比如开机默认关闭led灯,数码管段位选

     P0=0xff;P2=(P2&0x1f)|0x80;P2&=0x1f;//关ledbuzzer=0;relay=0;P2=(P2&0x1f)|0xa0; P2&=0x1f;//关蜂鸣器和继电器P0=0xff;P2=(P2&0x1f)|0xc0; P2&=0x1f;//关位选P0=0xff;P2=(P2&0x1f)|0xe0;P2&=0x1f;//关段选

(可以看到我每次都是先对P0进行操作,再对锁存器进行操作,这个一般用于初始化关闭蜂鸣器,led,数码管)

数码管

1.2 数码管(板载共集成8位共阳级数码管)数码管分段选和位选

段选:控制每一位数码管亮的二级管的个数,比如上面的a,b,c,d等等

比如:

0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff(低电平点亮)

0        1       2      3      4      5       6      7        8        9     全灭

位选:控制8位数码管中那几位点亮,比如com1-com8(高电平点亮)

对于静态数码管,直接选段,选位再点亮就行

对于动态数码管:利用人眼的视觉暂留,配合定时器中断,每2ms刷新一次,就能达到稳定的效果

emmmm,这里牵扯到定时器,干脆直接合着一起写了:

定时器:

对于比赛而已,算定时的时间是不可能手算的:我们有stcisp下载工具,一般定时选择12T

从这copy过去就可,使用的时候使能EA(全局总中断)和对于的定时器

注意:定时器的中断号:定时器0为1,而定时器1为3:,中断函数名可以任意写

使用:比如以下动态数码管

         #include "stc15f2k60s2.h"
u8 code     smg_index[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x7f,0xbf};
u8 DT[]={10,10,10,10,10,10,10,10};
u16 s=0;
u8 i=0;
void sys_init(){P0=0xff;P2=P2&0x1f|0x80;P2&=0x1f;P0=0;  P2=P2&0x1f|0xe0;P2&=0x1f;P2=P2&0x1f|0xc0;P0=0;  P2&=0x1f;P2=P2&0x1f|0xa0; P04=0;P06=0;P2&=0x1f;}
void Timer0Init(void)       //1000微秒@11.0592MHz
{AUXR |= 0x80;     //定时器时钟1T模式TMOD &= 0xF0;       //设置定时器模式TL0 = 0xCD;       //设置定时初值TH0 = 0xD4;        //设置定时初值TF0 = 0;       //清除TF0标志TR0 = 1;      //定时器0开始计时
EA=1;
ET0=1;
}void smg_show(unsigned char du,unsigned char wei){//   DT[S]  sP0=1<<wei;     P2=(P2&0x1f)|0xc0;//位选P2=P2&0x1f;P0=smg_index[du];    //段选P2=(P2&0x1f)|0xe0;P2=P2&0x1f;}void main(){while(1){sys_init(); //系统初始化关蜂鸣器等函数
Timer0Init();//初始化定时器//使用动态数码管
DT[0]=i++;//数码管第一位显示1
if(i>8)i=0;}}void Time0() interrupt 1{smg_show(DT[s],s);//只有0-7八位数码管变化if(++s==8){s=0;}}

每当DT[]数组里的数变化后,每次定时器中断则显示对于位修改的数,不修改,段选为0xff不显示。

1.3 矩阵键盘和独立键盘

独立键盘:跳线帽接 2 3

使用:

u8 key_val=0;P3=0xf0&P3|0xf0//判断if(!P30)key_val=7;else if(!P31)key_val=6;else if(!P32)key_val=5;else if(!P33)key_val=4;

矩阵键盘:跳线帽 接  1 2

以状态机的方式实现:

u8 key_scan(){static key_state=0,key_return=0;   //每次返回值和状态进来不会重置u8 key_press;switch(key_state){case 0:     //未按按键时的状态key_return=0;    //返回值置零P3=0x0f; P42=0; P44=0; key_press = P3&key_low;if(key_press != 0x0f)key_state=1;break;case 1:    //按键按下去后第一次进scan_key的状态,每按一次按键只会进来case 1一次P3=0x0f; P42=0; P44=0;key_press = P3&key_low;//key_low为0x0f 同理key_high为0xf0if(key_press != 0x0f){if(key_press==0x0e) key_return=7;if(key_press==0x0d) key_return=6;if(key_press==0x0b) key_return=5;if(key_press==0x07) key_return=4;P3=0xf0; P42=1; P44=1;key_press = P3&key_high;if(key_press==0xe0) key_return+=12;if(key_press==0xd0) key_return+=8;if(P42==0) key_return+=4;       key_state = 2;}break;case 2:    //按键一直按着的状态P3=0x0f; P42=0; P44=0;key_press=P3&key_low;if(key_press == 0x0f)   //放开按键后key_state = 0回到case 0{key_state = 0;}default:break;}return key_return;
}

C语言不好的注意:函数内有两个static 修饰的静态局部变量

静态局部变量,在函数里定义,就只能在这个函数里使用,同一个文档中的其他函数也是用不了的。由于被static修饰的变量总是存在内存的静态区。所以即使这个函数运行结束,这个静态变量的值不会被销毁(即不会被重新定义和赋值为0,这一点很多人刚开始忘记了),函数下次使用时仍能使用。

状态机的基本原理:分为初始的状态(case0)  按下的状态(case1)已经按下的状态(case 2),以轮询的方式查按键的状态(正如代码所示),其中key_return 可以用来记录按键是否被按着未松开。

细节可以参考:

蓝桥杯单片机之按键扫描(状态机)_昊月光华的博客-CSDN博客_基于状态机的按键扫描程序

1.4 数码管消影:

这是在之前的段选和位选上进一步消除影子,为达极致的显示:

参考理论:蓝桥杯单片机开发板的数码管的消影_昊月光华的博客-CSDN博客

数码管消影后的动态扫描算法,与上文写的smg_play相比

void smg_play(u8 du,u8 we){P0=0xff;lock(7);  //消影P0=0;P0=1<<we;   lock(6);P0=0xff;P0=SMGINDEX[du]; lock(7);}

1.5 按键的长按和短按(嵌套if实现)


/*功能:判断代码长按短按
长按执行临界操作或者是持续性操作
短按则执行单一操作因为不存在持续性*/
void los(u8 keys){//有按键按下if(key_v==keys&&!longf){longf=1;longt=0;}if(longf==1&&(longt++>1000)){  longf=2;DT[1]=9;执行长按达到临界值功能功能}if(longf==2&&(longt++%1000==0)){q++;DT[2]=q/10%10;DT[3]=q%10;}if((longf==1||longf==2)&&!key_v){//松开按键if(longt<=1000){//执行短按DT[1]=7;}longf=0;}}

效果:短按显示7 ,长按显示9(临界操作),后每隔1s显示q++的操作

1.6  按键的长按和短按(状态机实现)


/*功能:判断代码长按短按
长按执行临界操作或者是持续性操作
短按则执行单一操作因为不存在持续性*/void los(u8 keys){switch(longf){case 0:longt=0;DT[2]=0;DT[3]=0;if(key_v==keys)longf=1;break;case 1:if(key_v==keys){if(longt++>1000){//达到长按临界值执行长按的瞬间性操作DT[1]=9;longf=2;}}else {if(longt<=1000){ //执行短按DT[1]=7;}longf=0;}break;case 2:if(key_v==keys){if(longt++%1000==0)q++;//0-65535DT[2]=q/10%10;DT[3]=q%10;if(longt==60000)longt=0;//执行长按的连续性操作}else longf=0;break;}}

效果:短按显示7 ,长按显示9(临界操作),后每隔1s显示q++的操作,复位后q的显示消失。

常用外设

2.1 DS18B20温度传感器

该温度传感器是基于one wire 单总线协议

参考单总线协议(1-wire)的基本原理 - 知乎 (zhihu.com)

典型的单总线命令序列如下:

  • 第一步:初始化
  • 第二步:ROM命令(跟随需要交换的数据)
  • 第三步:功能命令(跟随需要交换的数据)

初始化:

时序见图 2.25-2 主机总线 t0 时刻发送一复位脉冲(最短为 480us 的低电平信号) 接着在 t1 时刻释放总线并进入接收状态 DSl820 在检测到总线的上升沿之后 等待 15-60us 接着 DS1820 t2 时刻发出存在脉冲(低电平 持续 60-240 us) 如图中虚线所示以下子程序在 MCS51 仿真机上通过 其晶振为 12M. 初始化子程序

sbit DQ=P1^4;
bit init_ds18b20(void)
{bit initflag = 0;DQ = 1;//这句不加也可以 Delay_OneWire(12);DQ = 0;Delay_OneWire(80);//拉低延长400-960usDQ = 1;Delay_OneWire(10);initflag = DQ;Delay_OneWire(5);return initflag;
}
void Delay_OneWire(unsigned int t)
{/*传统8051单片机是12T,而15单片机是1T,理论上应该扩大延时为12倍,实际上8-12倍都可以*/unsigned char i;while (t--){for (i = 0; i < 8; i++);}
}

ROM命令

 写时间间隙:(发送命令)

当主机总线to时刻从高拉至低电平时 就产生写时间隙见图2.25.3 2.25.4 to 时刻开始 15us 之内应将所需写的位送到总线DSl820 t15-60us 间对总线采样,若低电平写入的位是0,见图 2.25.3;若高电平写入的位是1见图2.25.4。连续写2位间的间隙应大于1us

void Write_DS18B20(unsigned char dat)
{unsigned char i;for (i = 0; i < 8; i++){DQ = 0;DQ = dat & 0x01;//将dat的最低位数据送总线Delay_OneWire(5);DQ = 1;dat >>= 1;//dat右移一位得次低位}Delay_OneWire(5);
}

读时间间隙:(读取数据)

 首先将数据线拉低然后延长4us,再将数据线拉高释放总线准备读取数据,延时10us,读数据线状态得到一个状态位并进行数据处理,延时45us,循环重复,直到读完一个字节(八位数据)


unsigned char Read_DS18B20(void)
{unsigned char i;unsigned char dat;for (i = 0; i < 8; i++){DQ = 0;dat >>= 1;DQ = 1;//采样信号,释放总线准备读取数据if (DQ){dat |= 0x80;}Delay_OneWire(5);}return dat;
}

功能命令

读取温度:

DS18B20是存取16位数据,分为高八位和低八位,高八位的高四位为符号位,低八位的低四位是小数位,其余为为整数位,另外ds18b20的资料代码中读取采样的数据是从低位开始读取。

获取温度函数编写

首先初始化设备,向单总线发送0xcc(ROM指令)指令,跳过ROM搜索,发送0x44(RAM命令如上图)指令开启温度转换。继续初始化设备,继续跳过ROM搜索,发送0xbe(RAM命令)读取命令。把读到的数据低八位赋值变量low,高八位赋值high。然后把数值转换成小数返回。


float rd_temperature(void)
{unsigned char low,high;/*用来存暂存器的值*/unsigned int temp;/*取整数*/float result;init_ds18b20();//搜寻总线上有没有DS18B20设备Write_DS18B20(0xcc);/*跳过rom搜索*/Write_DS18B20(0x44);/*开启温度转换*/init_ds18b20();//搜寻总线上有没有DS18B20设备Write_DS18B20(0xcc);/*跳过rom搜索*/Write_DS18B20(0xbe);/*告诉总线准备读取暂存器*///DS18B20 16位 高八位的低四位和低八位的高四位为整数low=Read_DS18B20();//低八位high=Read_DS18B20();//高八位temp =(high&0x0f);temp<<=8;temp|=low;result =temp*0.0625; return result;}

2.2 串口

 1:首先初始化串口

void UartInit(void) //9600bps@11.0592MHz
{SCON = 0x50;  //8位数据,可变波特率AUXR |= 0x40; //定时器1时钟为Fosc,即1TAUXR &= 0xFE; //串口1选择定时器1为波特率发生器TMOD &= 0x0F; //设定定时器1为16位自动重装方式TL1 = 0xE0;    //设定定时初值TH1 = 0xFE;    //设定定时初值ET1 = 0;   //禁止定时器1中断TR1 = 1;     //启动定时器1//ES=1;  //   ES EA 为中断控制位,若开启串口中断 若开启串口中断则还要写中断函数//EA=1;
}

2:写串口接受和发送函数

void send_char(unsigned char chr)//发送一个字节的数据
{SBUF = chr;while (!TI); //硬件发送以后自动置1TI = 0;
}void send_string(unsigned char *str)//发送一个字符串
{while (*str){send_char(*str);str++;}
}
void rear_char(unsigned char *p)//接受字符串
{char *temp;//字符临时变量if(RI){RI=0;*temp=SBUF;send_char(*temp);}

SBUF为发送和接受数据的缓冲区

SBUF=xxx(即为SBUF写在左边为发送数据)而xxx=SBUF(SBUF写在右边为接受数据)TI为发送数据的标志位,正在发送数据 TI硬件置0,发送完后硬件置1,为了连续发送故再软件置0。

3:使用串口

通过调用串口的接受和发送函数来使用串口。

2.3 超声波:

工作原理:

(简单的说,就是超声波配合计数器,发送方波后打开计时,然后计算时间乘以速度(340m/s)/2得距离)

需要注意的是想要计算的路程足够远,你计数器计时的时间得足够长,所有得用12T的模式,周期为1us,1T的周期为1/12us,最长时间1us*65535,最长距离

340*65535(ms)/1000000*100/2=0.017*65535(cm)(这也是计算公式)

sbit Tx=P1^0;
sbit Rx=P1^1;void Timer0Init(void)     //1微秒@11.0592MHz
{AUXR &= 0x7F;     //定时器时钟12T模式TMOD &= 0x0F;       //设置为计数器模式TL0 = 0x00;     //设置定时初值TH0 = 0x00;        //设置定时初值TF0 = 0;       //清除TF0标志TR0 = 0;      //定时器关闭计时
}void csb_start(void)
{u8 i=8;EA=0;//关闭总中断,防止其他中断占用cpu导致并未连续发送方波而计算不准确while(i--){Tx=1;Delay12us();Tx=0;Delay12us();}EA=1;
}unsigned int get_dis(void)
{u16 dis;Rx=1;csb_start();TR0=1;//开启计数器while((Rx==1 && TF0==0));//数据未溢出或是未接受到方波时继续等待TR0=0;//关闭计数器if(TF0==1)//判断数据溢出标准位{dis=999;TF0=0;TH0=0;TL0=0;}else//正常接受到方波{dis=(TH0<<8)|TL0;//高八位左移八位再或上低八位再赋给16位数据disTH0=0;TL0=0;dis=(dis*0.17)/10;if(dis <= 2 || dis >= 400)dis=999;}return dis;
}

2.4 iic总线

2.4.1iic总线概述:

• IIC 总线只有 2 根信号线,一根是 数据线 SDA ,一根是 时钟线 SCL 。 SDA 和 SCL 均为 双向信号线
• 当 总线空闲 时,两根线都是 高电平 。连接到总线上的任一器件,输出低电平,都将使总线的信号变低。

每个具有IIC接口的设备都有一个唯一的地址,也叫做设备地址

2.4.2 总线数据传输规范

• 在数据的传输过程中,必须确认数据传送的开始和结束。在 IIC 总线规范中,规定了起始信号和停止信号。
起始信号 :当时钟线 SCL 为高电平时,数据线 SDA 由高变低。
停止信号 :当时钟线 SCL 为高电平时,数据线 SDA 由低变高。
在起始信号之后 ,必须是器件的控制字节,也即是 设备地址 ,其中 4 是器件的类型识别符( EEPROM 的识别符为 1010 ),接着 3 是片选信号, 最后 1 是读写控制位,读操作为 1 ,写操作为 0 。
(类型识别符)                                            (片选信号位)                         (读写位)
• A0 , A1 , A2 为 24C02 的 片选信号 , IIC 总线最多可以挂载 8 个(A0,A1,A2能表示的最多项) IIC 接口器件,通过对 A0 , A1 , A2 寻址,可以实现对不同的 EEPROM 操作
什么是EEPROM:
EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。(可以理解为挂在总线上的可编程只读的外设)
• IIC 总线每次传送的数据字节不限, 每一个字节必须是 8 。数据传送时,必须先送最高位 (MSB) , 每个数据字节后面都有一个确认位 ,也就是应答 (ACK) 。

IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到。应答信号由接收方在数据开始后的第9个时钟周期发送,在SCL为高电平期间,接收方将SDA拉为低电平产生应答,用来结束一个字节的传输。也就是说,一帧完整的数据共有9位。      注意:当主机接收数据(也就是在读数据状态)时,它收到最后一个字节后,必须向从机发出一个结束传送的信号。这个信号是通过对从机的“非应答信号”来实现的,在SCL为高电平期间,SDA为高电平,即从机释放SDA线,允许主机产生一个停止信号。

写入时序:

读时序:

2.4.3 总线驱动程序设计

•在没有硬件IIC外设的微处理器中,需要根据总线时序设计IIC接口的驱动程序。包括:起始信号停止信号产生应答等待应答发送数据接收数据6个函数。

/*程序说明: IIC总线驱动程序软件环境: Keil uVision 4.10 硬件环境: CT107单片机综合实训平台 8051,12MHz日    期: 2011-8-9
*/#include "reg52.h"
#include "intrins.h"#define DELAY_TIME 5#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */void IIC_Delay(unsigned char i)
{do{_nop_();}while(i--);
}
//总线启动条件
void IIC_Start(void)
{SDA = 1;SCL = 1;IIC_Delay(DELAY_TIME);SDA = 0;IIC_Delay(DELAY_TIME);SCL = 0;
}//总线停止条件
void IIC_Stop(void)
{SDA = 0;SCL = 1;IIC_Delay(DELAY_TIME);SDA = 1;IIC_Delay(DELAY_TIME);
}//发送应答
void IIC_SendAck(bit ackbit)
{SCL = 0;SDA = ackbit;                    // 0:应答,1:非应答IIC_Delay(DELAY_TIME);SCL = 1;IIC_Delay(DELAY_TIME);SCL = 0; SDA = 1;IIC_Delay(DELAY_TIME);
}//等待应答
bit IIC_WaitAck(void)
{bit ackbit;SCL  = 1;IIC_Delay(DELAY_TIME);ackbit = SDA;SCL = 0;IIC_Delay(DELAY_TIME);return ackbit;
}//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{unsigned char i;for(i=0; i<8; i++){SCL  = 0;IIC_Delay(DELAY_TIME);if(byt & 0x80) SDA  = 1;else SDA  = 0;IIC_Delay(DELAY_TIME);SCL = 1;byt <<= 1;IIC_Delay(DELAY_TIME);}SCL  = 0;
}//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{unsigned char i, da;for(i=0; i<8; i++){   SCL = 1;IIC_Delay(DELAY_TIME);da <<= 1;if(SDA) da |= 1;SCL = 0;IIC_Delay(DELAY_TIME);}return da;
}

2.4.4 总线驱动程序的应用

2.4.4.1:

EEPROMAT24C02

AT24C02EEPROM芯片地址的固定部分为1010,片选端A2A1A0得到固定的3位编码.形成的7位编码即为该器件的地址码。

//EEPROM 写入
void AT24C02_WB(u8 ward,D)
{IIC_Start(); IIC_SendByte(0xa0); IIC_WaitAck();  IIC_SendByte(ward); IIC_WaitAck(); IIC_SendByte(D); IIC_WaitAck(); IIC_Stop();
}//EEPROM 读取
u8 AT24C02_RB(u8 ward)
{u8 D;IIC_Start(); IIC_SendByte(0xa0); IIC_WaitAck();  IIC_SendByte(ward); IIC_WaitAck(); IIC_Start(); IIC_SendByte(0xa1); IIC_WaitAck();D=IIC_RecByte();IIC_Stop();  return D;
}

2.4.4.2:

数模转换与模数转换(PCF8591)DAC与ADC

PCF8591是具有IIC接口的8位A/D和D/A转换芯片,具有4路模拟输入一路DAC输出和一个IIC总线接口

PCF8591的设备地址包括固定部分可编程部分。可编程部分需要根据硬件引脚A0、A1和A2来设置。设备地址的最后一位用于设置数据传输的方向,即读/写位。

PCF8591的设备的读操作地址为:0x91;而写操作地址则为:0x90

控制寄存器:

光敏传感器接到AIN1,通道1;控制寄存器应写入:0x01
电位器Rb2接到AIN3,通道3;控制寄存器应写入:0x03

void write_DAC(u8 dat)
{IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck();  IIC_SendByte(0x40); IIC_WaitAck(); IIC_SendByte(dat); IIC_WaitAck();  IIC_Stop();
} //DAC写入//adc读取
u8 ReadADC(u8 ain)
{u8 Data;IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck();  IIC_SendByte(ain); IIC_WaitAck(); IIC_Stop();  IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck();  Data=IIC_RecByte(); IIC_Stop();  return Data;
}

使用例如读取光敏传感器和RB2电位器的采样值,存取EPPROM。

AT24C02_RB(1);
AT24C02_WB(1,adc_val)//adc_val为要写入的值
ReadADC(0x03);//0x03 RB2电位器
ReadADC(0x01);//0x01 光敏传感

2.5 NE555频率测量

说明

这个NE555频率测量需要结合定时器0,并且设置为计数模式,按键,数码管等其他外设则用定时器1就行,NE555在数电中被叫做三五定时器,可用于构建单稳态电路,多谐振荡器和斯密特触发电路,在蓝桥杯(stc15f2k60s2)的开发板中,是通过调节RB3电位器的电阻值以调节脉冲频率。

使用

用竞赛板子上的P34与SIGNAL短接,用跳线帽或杜邦线(若题目不涉及超声波和红外则可借用超声波下方的跳线帽)。

void Timer0Init(void)
{AUXR |= 0x80;TMOD |= 0x05;    TL0 = 0x00;        //设置计数初值TH0 = 0x00;        //设置计数初值TF0 = 0;TR0 = 0;ET0 = 0;
}//初始化定时器0void Timer1Init(void)     //1000微秒@12.000MHz
{AUXR |= 0x40;     //定时器时钟1T模式TMOD &= 0x0F;       //设置定时器模式TL1 = 0x20;       //设置定时初始值TH1 = 0xD1;       //设置定时初始值TF1 = 0;      //清除TF1标志TR1 = 1;      //定时器1开始计时EA=1;ET1=1;
}//初始化定时器1//在main.c中u16 fr=0;//频率
u16 frtime=0;TR0=1;//开始计数
while(1){//读出1s的脉冲个数也就是频率
if(frtime==500){
frtime=0;
TR0=0;//结束计数
fr=TH0<<8|TL0;
TH0=0;
TL0=0;//清空高八位和低八位计数
fr*=2;//fr*2也就是1s中计数的脉冲个数
TR0=1;//开始下一次计数
}
//todo}void time1() interrupt 3{//定时器1中断函数 1ms产生一次中断frtime++;//to  do}

2.6 DS1302实时时钟

说明

其时序图文档中都有,而且比赛提供的资料中提供了底层代码,我们只需要调用就行了。

时序图:

读写命令

 //DS1302驱动文件提供的函数#ifndef __DS1302_H
#define __DS1302_Hvoid Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
#endif

使用

由于DS1302读和写的数据都是BCD码,一个字节高四位表示十位,低四位的数值即为剩余的数值。比如 0x15 BCD码为  0001  0101  转换为显示的十进制为1*10+5。

u8 DatToBcd(u8 dat)//数据转BCD码
{u8 dat1,dat2;dat1 = dat / 10;dat2 = dat % 10;dat2 = dat2 + dat1 * 16;return dat2;
}u8 BcdToDat(u8 dat)//BCD码转数据
{u8 dat1,dat2;dat1 = (dat >>4)*10;dat2 = (dat&0x0f) % 16;dat2 = dat2 + dat1;return dat2;
}

初始化写时间函数(如 写 年 周 月 日  时 分 秒)

void DS_INIT(){Write_Ds1302_Byte(0x8e,0);//清除写保护Write_Ds1302_Byte(0x80,DatToBcd(30));//30秒Write_Ds1302_Byte(0x82,DatToBcd(15));//15分Write_Ds1302_Byte(0x84,DatToBcd(15));//15时Write_Ds1302_Byte(0x86,DatToBcd(1));//日Write_Ds1302_Byte(0x88,DatToBcd(15));//15月Write_Ds1302_Byte(0x8a,DatToBcd(1));//周一Write_Ds1302_Byte(0x8c,DatToBcd(15));//15年}

读取时间函数(比如 年 周 月 日 时 分 秒)

void Read_Time(){MyDst[0]=BcdToDat(Read_Ds1302_Byte(0x8d));//年MyDst[1]=BcdToDat(Read_Ds1302_Byte(0x8b));//周MyDst[2]=BcdToDat(Read_Ds1302_Byte(0x89));//月MyDst[3]=BcdToDat(Read_Ds1302_Byte(0x87));//日MyDst[4]=BcdToDat(Read_Ds1302_Byte(0x85));//时MyDst[5]=BcdToDat(Read_Ds1302_Byte(0x83));//分MyDst[6]=BcdToDat(Read_Ds1302_Byte(0x81));//秒}

每隔1s定时读取时间就实现了实时时钟。

2.7  PWM的控制

参考应用

基于单片机的PWM输出对Led的常见应用_昊月光华的博客-CSDN博客

找个隐蔽的地方写:愿君能有所收获,正所谓  “何以与君识”,“无言码千行”。

国信长天单片机竞赛训练之原理图讲解及常用外设原理(遗失的章节-零)相关推荐

  1. 国信长天单片机竞赛训练之DS18B20温度报警实验(三)

    目标要求:通过板载的DS18B20获取温度,并在数码管上保留4位小数显示,温度超过25.0000度,蜂鸣器报警:低于等于25.0000度,所有LED间隔2秒闪烁:温度超过25.0000度,通过串口发送 ...

  2. 国信长天单片机竞赛训练之用定时器中断实现时钟(一)

    本次实现的(国信长天)蓝桥杯的一个单片机比赛,实现起来用定时器中断配合数码管实时显示,达到时钟效果. //main.c#include "sys.h"typedef unsigne ...

  3. 国信长天单片机竞赛训练之超声波实验(四)

    本次是第四次作业了,作业要求如下: 1.结合定时器知识,使用定时器1作为中断源,使用定时器0做计数器进行超声波测距,并在数码管上显示: 2.以第一种方式进行测距.当测试距离大于10cm,小于等于20c ...

  4. 国信长天单片机竞赛训练之通过iic光敏,电位器采样(五)

    本次培训内容学iic,要求实现:  开机显示光敏电阻的值,S4按键控制显示光敏电阻值,S5按键控制显示Rb2电位器的值,S8按键控制存数据进EEPROM,S9按键控制显示存入EEPROM的值. 代码如 ...

  5. 蓝桥杯国信长天单片机--硬件环境(一)

    CT107D 单片机由以下功能模块组成 1.功能模块 (1)单片机芯片 配置IAP15F2K61S2单片机 (2)显示模块 配置8路LED输出L1-L8 配置8位8段共阳极数码管DS1-DS2 配置L ...

  6. 蓝桥杯国信长天单片机--串口程序设计(十)

    实验目的: 1.掌握51单片机串口工作模式及相关寄存器配置方法 2.了解51单片机波特率的计算方法 3.掌握单片机串口接收中断服务函数的设计方法 程序说明: 1.通过USB连接线连接PC机,在计算机硬 ...

  7. 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.9 TIM---输入捕获(脉冲频率测量)实验

    写在前面-- <STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>第四章4.9 TIM-输入捕获(脉冲频率测量)实验,讲解TIM输入捕获的原 ...

  8. 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.1 LED显示控制实验

    写在前面-- <STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>第四章4.1,本节将通过LED显示控制实验,学习STM32G431的开发技 ...

  9. STM32单片机开发应用教程 (HAL库版) ---基于国信长天嵌入式竞赛实训平台(CT117E-M4)教程汇总 与第一章 硬件平台简介

    写在前面-- 作为<STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>教程汇总,第一章将介绍国信长天嵌入式竞赛实训平台(CT117E-M4) ...

最新文章

  1. 写一篇C语言入门第一讲
  2. ZooKeeper系列(4):ZooKeeper的配置文件详解
  3. DuiLib——xml节点元素属性介绍
  4. 邮件服务器 文件服务器,搭建邮件、终端和文件服务器应用方案_服务器_服务器x86服务器-中关村在线...
  5. vue设置一个简单的计算器
  6. Java魔法堂:URI、URL(含URL Protocol Handler)和URN
  7. React开发(259):react项目理解 ant design debug
  8. 使用swiper_关于使用swiper制作web轮播图
  9. Zookeeper应用:服务端上下线
  10. 【C#】ADO .Net Entities Framework使用查询语句时遇到的错误
  11. 数据库msqlserver的几种类型及解决MSSQLServer服务启动不了的问题
  12. Linux音频驱动-ASOC之Machine
  13. oracle的sql字符串转义,sql – 在Oracle数据库中搜索带转义的字符串
  14. TCP客户端和服务端的互通信息
  15. 程序员的贫富两极分化,穷的穷死,富的富死,我就是那“穷鬼”?
  16. 围绕禅道介绍公司流程
  17. 「OceanBase 4.1 体验」|快速安装部署
  18. 陆奇最新演讲高清PPT下载;AI 绘画20+工具体验汇总;我愿称MOSS为全球开源界最强;思否AIGC黑客马拉松北京站 | ShowMeAI日报
  19. 数据增强方法——Back translations(反向翻译)
  20. 云计算技术基础期末复习

热门文章

  1. OpenGLES(一)——介绍
  2. android arp 检测工具,android检测arp攻击
  3. ubuntu中英文输入法切换方法
  4. html中的doctype有什么作用,html中doctype的作用是什么?
  5. L4公司进军辅助驾驶,放话无图也能跑遍中国
  6. 互联网赋能医疗产业流通,让企业告别低能效高成本运作模式
  7. 基于Quartues ii和Modelsim的FIR滤波器仿真
  8. 按键连续点击的c语言程序,【转】按键长按与短按处理程序[C语言]--通過測試
  9. 孙文智/胡霁/汪小京团队揭示延迟满足的神经基础
  10. 每天学点GDB 12