2018-12-06 18:20:23 h_5649512 阅读数 304
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3396 人正在学习 去看看 朱有鹏

单片机制作工具大汇总!!

单片机制作工具大汇总!!!这是一个神奇的帖子,我不会放很多的资料出来,我只放一个列表,大家需要哪个资料就回复告诉我,我再上传,然后先上传几个工具给大家玩玩:可以到闯客网技术论坛下载,下面是参与本次分享的选手,如果急需的话,可以到Q群q我:813238832
单片机工具下载:https://bbs.usoftchina.com/thread-206209-1-1.html
LC谐振频率计算器.rar (4.63 KB
LCD图形生成.rar (256.3 KB
LCD防真器.zip (261.05 KB
commix.rar (188.21 KB
comdebug.rar (155.62 KB
ComAssistant.rar (197.66 KB
BMP生成PCB格式软件.rar (489.13 KB
BMPtoPCB.rar (110.1 KB
Bin_Hex.rar (204.8 KB
AvrCalc_eehome.rar (20.49 KB
AT89ISP.rar (1.1 MB
Afilter.rar (215.75 KB
1616汉字取模.rar (208.74 KB
890LC谐振回路计算.rar (4.63 KB
875电流源在线计算器离线网页.rar (4.45 KB
750定时器计算器.rar (4.72 KB
645规约调试助手.rar (395.08 KB
645规约调试助手.rar (395.08 KB
555设计.rar (368.3 KB
51单片机反反汇编器.rar (247.68 KB
51单片机定时器初值计算器.rar (6.79 KB
51单片机串行口初值计算器.rar (10.13 KB
51波特率初值设定.rar (175.71 KB
51波特率初值计算.rar (179.05 KB
51Hex_Bin.rar (213.9 KB
16.16LED点阵字库软件.rar (27.03 KB
8X8点阵取模软件.rar (10.1 KB
8.8LED点阵字库软件.rar (75.94 KB
LCD防真器.zip (261.05 KB
LC谐振频率计算器.rar (4.63 KB
LC谐振频率计算器V1.20.rar (5.45 KB
LED代码提取.rar (3.64 KB
LED段码提取.rar (183.48 KB
LED数码管字形码发生器.rar (10.2 KB
LM317计算.rar (803.42 KB
lm317设计工具.rar (178.81 KB
mcutool.rar (431.93 KB
MuCodeISP-0.18.rar (46.26 KB
p_hcs301enc.rar (174.29 KB
PCB特性阻抗计算工具软件TXLine.rar (411.31 KB
progisp167.rar (1.11 MB
Protel 99 SE 鼠标增强软件 V3[1][1].0.rar (542.53 KB
usbDebug V1[1].rar (106.26 KB
USBISP下载线资料.rar (1.46 MB
变压器计算.rar (1.07 MB
变压器设计软件.rar (1.65 MB
超级单片机工具.rar (433.5 KB
串口助手.rar (392.58 KB
单片机设计助理 V2[1].4 破解版.rar (1.38 MB
单片机小精灵.zip (688.79 KB
单片机延时计算小程序.rar (8.21 KB
单片机正弦波数据生成器.rar (1.14 MB
单片机正弦波数据生成器.rar (1.14 MB
点整取模小工具.rar (658.92 KB
点整取模小工具.zip (772.86 KB
电感量计算.rar (69.87 KB
电容单片转换CCT.rar (96.51 KB
电阻并联计数器.rar (16.34 KB
洞洞板板上画PCB的专业工具.rar (581.04 KB
更好用的1616汉字取模.rar (164.29 KB
工程单位转换.rar (74.34 KB
汉字生成器(软件).rar (254.06 KB
画流程图.rar (686.91 KB
汇编语言程序库.rar (447.97 KB
计算器.rar (173.1 KB
进制转换.rar (6.07 KB
空心线圈电感量的计算.rar (166.58 KB
取字模软件.rar (1.38 MB
熔丝位软件.rar (45.78 KB
软件延迟时间计算分析.rar (63.3 KB
色环电阻识别程序.rar (75.79 KB
声谱分析器–(50K)很精巧的程序.zip (1.27 MB
实用计算器.rar (69.14 KB
示波器.rar (1.16 MB
数制转换小程序.rar (213.32 KB
衰减器计算器.rar (7.56 KB
炜煌串口调试软件.rar (13.83 KB
显示器测试软件NokiaMonitorTest.rar (325.31 KB
小精灵电气计算.rar (84.56 KB
晓刚电阻值计算.rar (687.88 KB
虚拟示波器.rar (60.85 KB
液晶字模生成程序2.0.rar (209.64 KB
液晶字模提取软件.rar (385.89 KB
一种实用线圈参数计算软件.rar (69.92 KB
音乐代码转换.rar (211.06 KB
在protel99se软件PCB里面放汉字的实现.rar (1.31 MB
正弦波数据生成器(正弦波表).rar (37.53 KB
中断延迟时间…rar (18.42 KB
终极串口调试软件.rar (74.23 KB
专业工具.rar (259.09 KB
字模提取.rar (240.75 KB
字模提取V2.2.rar

再给你们附送点资料:

在这里插入图片描述

2017-07-25 12:53:30 wangwangpengpeng 阅读数 39716
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3396 人正在学习 去看看 朱有鹏
利用51单片机制作一个秒表的详细过程

前面的话:

和很多朋友一样,在学51单片机的过程中我们肯定会涉及到制作一个秒表,牵涉到把单片机的多个部分组合起来使用,这对于我们初学者来说可能显得有些困难,我同大家一样,百思不得其解,最后头都弄大了才把这个秒表制作出来,为了给以后的朋友们一些思路,一些参考,所以在这里我把自己制作的整个详细过程整理出来供大家参考。我调试出来是没有问题的,各方面都稳定运行,由于我水平有限,中间可能会有不对的地方,欢迎大家指正,我们一起学习,一起进步!

我将分为三个部分来介绍:1.整体思路,2.硬件电路方面,3.软件编程方面。


1.整体思路

利用51单片机制作秒表时,我介绍精确到十分位(即0.1s)的制作,并让其拥有启动,暂停,复位三个功能。
用到的单片机部分:定时器部分,独立按键的检测与应用,数码管的显示,并结合一些简单的程序即可实现。
用5位数码管来进行显示,分别显示秒的十分位,秒的个位,秒的十位,分的个位,分的十位。用定时器定时50ms,2个定时器中断即是0.1s,即秒的十分位,20个定时器中断即是1s,60个1s即是1分钟,通过程序将5位数码管的值分离出来,并进行显示。这就是我在数码管显示方面的思路,如果不是太清楚,结合我下面软件编程方面的程序来看你可能就会明白,我会在那部分做详细介绍,看完了可能你就懂了。
利用独立按键设置启动/暂停键和清零键,利用独立按键的检测,若启动/暂停按键按下,秒表则启动或者暂停,按下复位键,秒表清零复位。我在程序后面全都有注释,不用担心。看完你就会明白了。
这是我制作的的流程图:




“ms100”表示秒的十分位,"s"表示秒的个位,“s1”表示秒的十位,“min”表示分的个位,“min1”表示分的十位。
“cnt”表示秒的计数位,即多少个一秒,定时满一秒加1,“minu”表示分的计数位,即多少个一分钟,一分钟加1,
这个流程图提供了大致思路,要结合下面的程序部分一起看。可能有些简陋,请多多包涵!


看起来是不是好简单?有木有?请继续往下看。

2.硬件电路方面

每个人的硬件可能都不一样,(哪些控制数码管的位选,哪些控制数码管的段选,哪些控制独立按键等等),大家在自己制作过程中都要仔细考虑,我在这里就用我自己的硬件进行介绍。

这是我的数码管的电路图:(将J12用杜邦线接到对应的P0口,将J16用杜邦线接到对应的P1口)


位选端我用P1口控制,段选端我用P0口控制。在图中我已标明秒的个位s,秒的十位s1,分的个位min,分的十位min1所对应的数码管。该数码管是共阴极。
秒的十分位我用的是另一个共阳数码管。我用P3口控制该数码管的段选,其图如下:



而独立按键我用的P2^7控制“启动/暂停键”,P2^6控制复位键:电路图如下:(将JP5通过杜邦线接到P3口)

硬件电路基本上就是这些,由于分和秒之间要用小数点分隔开,所以分的个位对应的数码管的段码要用带小数点的段码,其余的数码管则不用。

硬件方面是为看懂软件程序做准备,下面我们就开始我们的软件程序方面吧!  

3.软件程序方面


#include <REGX51.H>
#define uchar unsigned char
#define uint unsigned int

#define PIN0 P0  //数码管段选端
#define PIN1 P1  //数码管位选端
#define PIN3 P3	 //十分位数码管的段码端
sbit start=P2^7;  //启动/暂停按钮
sbit reset=P2^6;  //复位按钮
uint cnt=0;   //1s的次数的计数值
uint num=0;     //进入中断次数的计数值(一次50ms)
uint num1=0;		//0.1s的次数的计数值
uchar code table[]={0x3f,0x06,0x5b,
0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f};
//不带小数点的共阴极数码管段码0-9
uchar code table1[]={0xbf,0x86,
0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
//带小数点的共阴极数码管段码0-9

char code table2[]={0xc0,0xf9,0xa4,
0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//不带小数点的共阳极数码管段码0-9

void Display(uint w,uint a,uint b,uint c,uint d);  //声明显示函数
void InitTimer0();  //声明定时器初始化函数
void Delayms(uint x);  //声明延时函数

void main()
{
	uint ms100=0;	//秒的十分位
	uint s,s1,min,min1,minu=0; 
	//依次是秒的个位,秒的十位,分的个位,分的十位
	InitTimer0();	  //初始化定时器
	while(1)			//进入死循环
{	
	if(start==0)   //检测启动/暂停键是否按下
			Delayms(20); //延时消抖
	{
		if(start==0)  //消抖之后再次检测
		{
			TR0=!TR0;		//定时器的控制位取反
			while(!start);  //等待按键释放
		}
	}
	
if(reset==0)  //检测复位键是否按下
{
	Delayms(20);	//延时消抖
	if(reset==0)  	//消抖之后再次检测
	{
		num=0;		
		num1=0;		//进入中断次数值清0
		ms100=0;	//十分位的计数值清0
		cnt=0;		//秒的计数值清0
		minu=0;		//分的计数值清0
		while(!reset);		 //等待按键释放
	}
}
	if(num1>=2)		//检测是否达到0.1s,(两个50ms)
	{
		num1=0;  		//进入中断次数值清零
		ms100++;		//秒的十分位的计数值加1
		if(ms100>=10)  //若秒的十分位计数值达到10
		{
			ms100=0;  //清零秒的十分位的计数值
			num1=0;	//进入中断次数值置0
		}
	}
	
	if(num>=20)  //判断计时时间是否达到1s(20个50ms)
	{
		num=0;     //进入中断次数值置0
		cnt++;		 //秒的计数值加1
		if(cnt>=60) //判断是否达到60s
	{
		cnt=0;		//若达到60s,将秒的计数值置零
		minu++;			//分的计数值加1
		if(minu>=60)  //判断是否达到60分钟,一般秒表是用不到60分的,这是为了程序的严谨性

		{
			TR0=!TR0;			//达到60分钟则关闭定时器并清零所有的计数值
			num1=0;				
			num=0;
			ms100=0;
			cnt=0;		
			minu=0;
			
		}
	}
	}	
	s=cnt%10;  	//从秒的计数值里面分离秒的个位
	s1=cnt/10; 	//从秒的计数值里面分离秒的十位
	min=minu%10;	//从分的计数值里面分离分的个位
	min1=minu/10;	//从分的计数值里面分离分的十位
	
	Display(ms100,s,s1,min,min1);  //显示这5个数
}	
}

void InitTimer0() //定时器初始化函数
{
	
	TMOD=0x01; //选择定时器0的工作方式1
	TH0=(65536-45872)/256;  //装初值(定时50ms),晶振11.0592MHz
	TL0=(65536-45872)%256;
	EA=1;		//打开总中断
	ET0=1;	//打开定时器中断
	TR0=0;	//先不要启动定时器
	
}

void TIMER0()  interrupt 1  //定时器中断服务函数
{
	TH0=(65536-45872)/256;  //重装初值
	TL0=(65536-45872)%256;
	num++;		//让进入中断次数值加1,用于判断是否达到1s
	num1++;		//让进入中断次数值加1,用于判断是否达到0.1s
}

void Delayms(uint x)   //延时xms
{
	uint i,j;
	for(i=x;i>0;i--)
		for(j=110;j>0;j--);
}

void Display(uint w,uint a,uint b,uint c,uint d) //定义显示函数
{
	PIN3=table2[w];		//秒的十分位的段选
	Delayms(5);
	
	PIN0=table[a]; //秒的个位的段选
	PIN1=0x7f;		 //秒的个位的位选
	Delayms(5);			
	
	PIN0=table[b];  //秒的十位的段选
	PIN1=0xbf;			//秒的十位的位选
	Delayms(5);
	
	PIN0=table1[c];  //分的个位的段选(带小数点)
	PIN1=0xdf;			 //分的个位的位选
	Delayms(5);
		
	PIN0=table[d];		//分的十位的段选
	PIN1=0xef;				//分的十位的位选
	Delayms(5);		
		
}

由于在打字时可能不小心会弄错一丁点程序,我都是一个字母一个字母手打的,所以请大家理解思路即可,根据这个思路自己去写,这样得到的知识才是属于自己的。毕竟 “读别人的故事,悟自己的人生”。
下面来几张实物图给大家看一下我这个秒表的实际效果。

编译结果:





烧写进单片机的效果:(没有按启动按钮之前)






按了启动按钮之后,秒表将会自动开始计时,由于无法演示动态过程,只能在中间按下暂停键给大家看看效果:











按下复位键后:



由于我用的是一个比较完整的51开发板,所以里面有很多部分,大家只需要注意观察数码管部分就好。
下面再来一个完整的图:





结束语

至此,利用51单片机制作的秒表就已经完成了!若是文章中有什么不懂的地方或者是自己在制作过程中遇到什么问题都可以联系我,或者给我留言,我一定竭尽全力帮助大家!我们一起学习,一起进步!希望大家都能在看完这篇文章后自己动手成功制作出一个秒表,祝愿大家学好单片机!当然,由于自身水平有限,文章中肯定会存在错误或者是考虑不周的的地方,恳请不吝赐教!谢谢大家!

(PS:我写了一整天了,反复的看,反复的改,现在头昏眼花,但是只要能对大家有所帮助,一切都是值得的。)




2017-12-02 20:40:42 non_mainstream 阅读数 614
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3396 人正在学习 去看看 朱有鹏

        51单片机制作计算机,我利用的是矩阵键盘和1602.  

在这个过程中难度较大的是PCB的制作。遇到了许多问题,布线规则,先款,孔径大小等等

在写程序的过程中难度较大的还是如何将键盘扫描与运算程序连接起来。。。。

在这个过程中还是学到了很多,对键盘扫描函数更加的熟练,对51单片机如何实现部分c语言

功能有一定的了解。


2018-08-14 04:57:10 qq_40730335 阅读数 1263
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3396 人正在学习 去看看 朱有鹏

#初学利用C语言和51单片机制作一个可调节时间和闹钟的keil程序与proteus仿真

本程序与仿真由******共同学习完成。欢迎讨论。

  • 51萌新
  • 第一次博客
  • 学习记录
  • keil
  • proteus

#keil代码
/****2018年8月14日凌晨3点37分封档完成****/

#include"reg52.h"
#define uchar unsigned char
#define uint unsigned int
#define XIANSHI shi,fen,miao  
#define SHISHE shi,99,99	 //99是任意一个数用于后面条件检测
#define FENSHE 99,fen,99
#define MIAOSHE 99,99,miao
#define NAO_S nao_s,99,99	   //闹钟的宏
#define NAO_F 99,nao_f,99
#define NAO_M 99,99,nao_m     //宏定义结束
sbit key1=P3^0;
sbit key2=P3^1;
sbit key3=P3^2;

sbit duan_1 =P2^0;		   //虽然声明是duan但是其实是用来位选的
sbit duan_2 =P2^1;
sbit duan_3 =P2^2;
sbit duan_4 =P2^3;
sbit duan_5 =P2^4;
sbit duan_6 =P2^5;
sbit huxiled=P2^6;		  //呼吸灯
sbit nzled=P3^3;		  //D2灯用来指示设置的闹钟时间到

uchar shijian[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};	 

uchar shi,fen,miao,nao_s=6,nao_f=0,nao_m,num_1=0,num_2=0,b=1,c=0;
uchar a=0,n=0;					  
			
void delayms(uint x)
{
	uint a,b;
	for(a=x;a>0;a--)
		for(b=110;b>0;b--);
}

void xianshi(uchar S,F,M)		   //时间和闹钟显示函数
{
	uchar shi_1,shi_2,fen_1,fen_2,miao_1,miao_2;

	shi_1=S/10;shi_2=S%10;
	fen_1=F/10;fen_2=F%10;
	miao_1=M/10;miao_2=M%10;
	
	if(S==99) {shi_1=10;shi_2=10;}//和设置按键有关,为了单独显示某一时或者分、秒。
	if(F==99) {fen_1=10;fen_2=10;}
	if(M==99) {miao_1=10;miao_2=10;}

	duan_1=1;P0=shijian[shi_1];delayms(5);duan_1=0;	  //位选
	duan_2=1;P0=shijian[shi_2];delayms(5);duan_2=0;
	duan_3=1;P0=shijian[fen_1];delayms(5);duan_3=0;
	duan_4=1;P0=shijian[fen_2];delayms(5);duan_4=0;
	duan_5=1;P0=shijian[miao_1];delayms(5);duan_5=0;
	duan_6=1;P0=shijian[miao_2];delayms(5);duan_6=0;


}

void keyscan()
{
	uint time=0;
	if(key1==0)
	{
		while(!key1) 
		{
			time++;
			if(time>40000){a=5;break;} //这是一个长按进入闹钟模式设置键
		}
		if(time<39999)	
		a++;
	}
	if(key2==0)						   //key2控制时间加
	{
		delayms(90);
		if(key2==0)
		{
			if(a==1) {delayms(90);shi++;if(shi==24) shi=0;}	
			if(a==2) {delayms(90);fen++;if(fen==60) fen=0;}
			if(a==3) {delayms(90);miao++;if(miao==60) miao=0;}
			if(a==6) {delayms(90);nao_s++;if(nao_s==24) nao_s=0;}
			if(a==7) {delayms(90);nao_f++;if(nao_f==60) nao_f=0;}
			if(a==8) {delayms(90);nao_m++;if(nao_m==60) nao_m=0;}
		}while(!key2);
	}
	if(key3==0)						  //key3控制时间减
	{
		delayms(90);
		if(key3==0)
		{
			if(a==1) {delayms(90);shi--;if(shi>=0&&shi<24);else shi=23;}
			if(a==2) {delayms(90);fen--;if(fen>=0&&fen<60);else fen=59;}
			if(a==3) {delayms(90);miao--;if(miao>=0&&miao<60);else miao=59;}
			if(a==6) {delayms(90);nao_s--;if(nao_s>=0&&nao_s<24);else nao_s=23;}
			if(a==7) {delayms(90);nao_f--;if(nao_f>=0&&nao_f<60);else nao_f=59;}
			if(a==8) {delayms(90);nao_m--;if(nao_m>=0&&nao_m<60);else nao_m=59;}	
		}while(!key3); 
	}
	if(a==4||a==9){a=0;}			 //归零
}

void init()
{
	nzled=0;   //给D2灯一个预设熄灭
	TMOD=0x01; //工作方式2

	TH0=0x4C;  //定时器T0
	TL0=0x00;
	ET0=1; 
	ET1=1;

	TH1=0xDC; //定时器T1
	TL1=0x00;
	ET0=1; 
	ET1=1;
	TR1=1; 

	EA=1;	 //总中断
}

void nzled()			  //闹钟和时间一致时让数码管和D2一起在将近10秒内频闪不断
{
	uint g;
	for(g=0;g<23;g++)
	{
		nzled=1;
		delayms(200);
		xianshi(XIANSHI);
	    nzled=0;
		delayms(200);
		xianshi(XIANSHI);
	}	
}

void main()
{
	init();
	while(1)
	{	
		switch(a)
		{	
			case 0:TR0=1;keyscan();xianshi(XIANSHI);break;
			case 1:TR0=0;keyscan();xianshi(SHISHE);break;//中断关闭时间停止
			case 2:keyscan();xianshi(FENSHE);break;
			case 3:keyscan();xianshi(MIAOSHE);break;
			case 5:;
			case 6:keyscan();xianshi(NAO_S);break;
			case 7:keyscan();xianshi(NAO_F);break;
			case 8:keyscan();xianshi(NAO_M);break;
		}
		if(a==0&&(nao_s==shi&&nao_f==fen&&nao_m==miao))nzled();	 //闹钟与时间一致进入nzled函数
	}
}

void zhongduan1() interrupt 1		//精确计时
{
	TH0=0x4C;
	TL0=0x00;
	num_1++;
	if(num_1==20)
	{
		num_1=0;
		miao++;
		if(miao==60)
		{
			miao=0;
			fen++; 
			if(fen==60)
			{
				fen=0;
				shi++;
				if(shi==24) shi=0;	
			}
		}
	}
}

void zhongduan2() interrupt 3	
//呼吸灯程序,具体体现为D1灯,
//在proteus中无呼吸效果猜测是因为proteus模拟时每次刷新每帧是0.05秒太久
//人眼捕捉在25帧,即使使用了PWM原理还是难以在proteus仿真中出现
//此呼吸灯并未上网查资料,欢迎讨论:alpha_LCL QQ:1143272695
{
	TH1=0xDC;
	TL1=0x00;
	num_2++;
	if(b<=6)
	{
		if(num_2<b) huxiled=1;
		else huxiled=0;
	}
	else
	{
		if((num_2+6)<b) huxiled=0;
		else huxiled=1;	
	}
	if(num_2==6)
	{
		num_2=0;c++;
		if(c==4)
		{
			b++;c=0;
			if(b==13) b=0;
		}
	}
}

#proteus中仿真
这里写图片描述

#使用方法
开始仿真后数码管将从00点00分00秒自动计时,轻击按键一将进入调试时间模式,第一次按下弹起后先调试00时,按键二为时间加、按键三为时间减。第二次按下后调试00分,按键二、三同理。第三次调试00秒,第四次调试完成返回。
长按按键一看到数码管闪烁后将进入闹钟调试模式,与时间调试模式同理。当时间和设置的闹钟时间相同时,D2灯和数码管会频闪10秒以示闹钟时间到。

2019-11-10 16:14:01 qq_44868609 阅读数 65
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3396 人正在学习 去看看 朱有鹏

此温控系统是基于stc89c52单片机制作,实现在1602上显示温度,并且可通过按键输入温度设定值,最后由PID调节温度。
由于本人初学者,水平有限,如有错误,欢迎大家留言纠正。以下是全部代码。。


#include <reg52.H>
#include <intrins.H>
#include <math.H>
#define uchar unsigned char
#define uint unsigned int
sbit ds = P0^0;
sbit RS = P0^2;    
sbit LCDEN = P0^1;   //1602使能端
sbit control=P0^4;   //PWM输出引脚
sbit led=P0^3;
uint time,PID_T;
uchar flag,lshi=3,lge=0;
/**//*****************************函数初始化*******************************/
void diaplayPID_En(int date);
/*************按键函数***********/
void adjust();  
void inc();    
void dec();
void keyscan();  
//延时函数
void delayUs();
void delayMs(uint a);
void writeComm(uchar comm);
void writeData(uchar dat);
void writeString(uchar * str, uchar length);
void init();
void dsInit();
void dsWait();
bit readBit();
unsigned char readByte();
void writeByte(unsigned char dat);
void sendChangeCmd();
void sendReadCmd();
int getTmpValue(); 
void diaplaypout(uint date);
void display(int v);
typedef struct PID_value   //结构体存放PID参数
{
		float Kp;
		float T;
		float Ti;
		float Td;
		uint setv;    //设定温度值
		float En;
		float En_1;
		float En_2;
		int PWMv_cur;  //当前应输出的PWM
		int pv;      //当前温度值
	
}PID_valuestr;
PID_valuestr PID;

void PID_config()  //具体PID参数根据自己的实际情况设定
{
	PID.Kp=40;
	PID.T=500;
	PID.Ti=3560;
	PID.Td=3000;
	PID.setv=300;
	PID.En_1=0;
	PID.En_2=0;
	PID.En=0;
	PID.PWMv_cur=40;	  //pwm周期为100ms
}
void PIDdeal()
{
	float tp,pwmout,p,PID_ti,ti,PID_td,td;
	if(PID_T>500)
  {	
  	writeComm(0x80+10);
	writeData(0x20);
	PID.En=PID.setv-PID.pv;	   //计算En	
	p=PID.En-PID.En_1;
	writeComm(0x80+11);
	diaplayPID_En(PID.En);
	tp=p*PID.Kp;
	PID_ti=PID.T/PID.Ti;
	ti=PID_ti*PID.Kp*PID.En;
	PID_td=PID.Td/PID.T;
	td=PID.Kp*PID_td*(PID.En-2*PID.En_1+PID.En_2);
	pwmout=tp+ti+td;
	PID.PWMv_cur+=pwmout;

	if(PID.PWMv_cur>100)
	{
		PID.PWMv_cur=100;
	}
	if(PID.PWMv_cur<0)
	{
		PID.PWMv_cur=0;
	}
	PID.En_2=PID.En_1;
	PID.En_1=PID.En;
	writeComm(0x80+0x40+11);
	diaplaypout(PID.PWMv_cur);
	PID_T=0;
  }

}
void delay(uchar z)
{
	uchar x,y;
	for(x=z;x>0;x--)
		for(y=110;y>0;y--);
}

 
void main()
{

    uchar table[] = "sv:30";
	uchar i;
    sendChangeCmd();
    init();
    writeComm(0x80);
	for(i=0;i<5;i++)
	writeData(table[i])	;
	PID_config();
    while(1)
    {
		PIDdeal();
        
		if(time>200)	  //500ms检测一次温度
		{
		
        	display(getTmpValue());
        	sendChangeCmd();
			time=0;
		}
		keyscan();
		led=0;
    }
}
void timer0() interrupt 1
{	
	uchar pwm ;

	TH0=(65535-1000)/256;
	TL0=(65535-1000)%256;
	pwm++;
	PID_T++;
	time++;
	if(pwm<=PID.PWMv_cur)
	{
		control=0; 
	} 
	else
	{
		control=1;
	}
	if(pwm==100)
	 pwm=0;
}
//PID


void display(int v) 
{
    unsigned char count;
    unsigned char datas[] = {0, 0, 0, 0, 0};
    unsigned int tmp = abs(v);
    datas[0] = tmp / 10000;
    datas[1] = tmp % 10000 / 1000;
    datas[2] = tmp % 1000 / 100;
    datas[3] = tmp % 100 / 10;
//    datas[4] = tmp % 10;
    writeComm(0xc0);
    if(v < 0)
    {
        writeString("- ", 1);
   }
    else
    {
       writeString("+ ", 1);
    }
    if(datas[0] != 0)
    {
        writeData('0'+datas[0]);
    }
    for(count = 1; count != 4; count++)
    {
        writeData('0'+datas[count]);
        if(count == 2)
        {
            writeData('.');
        }
    }
}
int getTmpValue()
{
    unsigned int tmpvalue;
    int value; 
    float t;
    unsigned char low, high;

    sendReadCmd();
 	ET0=0;
    low = readByte(); 
    high = readByte();
   	ET0=1;
    tmpvalue = high;
    tmpvalue <<= 8;
    tmpvalue |= low;
//	ET0=1;
    value = tmpvalue;
  \
    t = value * 0.0625;
    \
    value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
	PID.pv=value/10;
    return value;
	
}
void sendReadCmd()
{
	ET0=0;
    dsInit();
    dsWait();
	ET0=1;
    delayMs(1);
	ET0=0;
    writeByte(0xcc); 
    writeByte(0xbe); 
	ET0=1;
}
void sendChangeCmd()
{
	ET0=0;
    dsInit();    
    dsWait();
	ET0=1;   
    delayMs(1);
	EX0=0;    
    writeByte(0xcc);
    writeByte(0x44);
	ET0=1;
}
void writeByte(unsigned char dat)
{	
    unsigned int i;
    unsigned char j;
    bit b;
//	ET0=0;
    for(j = 0; j < 8; j++)
    {
        b = dat & 0x01;
        dat >>= 1;
    
        if(b)   
        {
           ds = 0;          i++; i++;  
            ds = 1;    
            i = 8; while(i>0) i--;  
        }
        else  
        {
            ds = 0;
          i = 8; while(i>0) i--;  
            ds = 1;
           i++; i++;
        }
	//	ET0=1;
   }
}
unsigned char readByte()
{
    unsigned int i;
    unsigned char j, dat;
   dat = 0;
    for(i=0; i<8; i++)
    {
        j = readBit();
      
        dat = (j << 7) | (dat >> 1);
    }
    return dat;
}

bit readBit()
{
    unsigned int i;
    bit b;
	ET0=0;
    ds = 0;
    i++;   
    ds = 1; 
   i++; i++;  
    b = ds;
    i = 8; 
    while(i>0) i--;
	ET0=1;
    return b;
}
void dsWait()
 {
      unsigned int i;
	  ET0=0;
      while(ds);  
      while(~ds);
      i = 4;
      while(i > 0) i--;
	  ET0=1;
}
void dsInit()
 {
    
    unsigned int i;  
	ET0=0;
    ds = 0;
    i = 100;  
    while(i>0) i--;
    ds = 1;   
    i = 4;
    while(i>0) i--;
	ET0=1;
 }
 void writeString(uchar * str, uchar length)
{
     uchar i;
    for(i = 0; i < length; i++)
    {
         writeData(str[i]);
     }
 }
  void init()
 {
	TMOD=0x01;   
	TH0=(65535-1000)/256;
	TL0=(65535-1000)%256;
	EA=1;
	ET0=1;
	TR0=1;
    writeComm(0x38);
    writeComm(0x0c); 
    writeComm(0x06);
    writeComm(0x01);
	led=0; 

}
//写数据:RS=1, RW=0;
void writeData(uchar dat)
{
     RS = 1;
     P2 = dat;
     LCDEN = 1;
    delayUs();
    LCDEN = 0;
    delayMs(1);
 }
void writeComm(uchar comm)
{
     RS = 0;    
    P2 = comm;
    LCDEN = 1;
     delayUs();
    LCDEN = 0;
    delayMs(1);
}
 void delayMs(uint a)
{
    uint i, j;
    for(i = a; i > 0; i--)
        for(j = 100; j > 0; j--);
 }
 void delayUs()
{
    _nop_();
}
void diaplaypout(int date)
{
	char bai,shi,ge;
	if(date<0)
	{
		writeComm(0x80+10);
		writeData('-');
		date=abs(date);
	}
	bai=date/100;
	shi=date%100/10;
	ge=date%10;

	writeData(0x30+bai);
	writeData(0x30+shi);
	writeData(0x30+ge);

}
void diaplayPID_En(int date)
{
	char bai,shi,ge;
	if(date<0)
	{
		writeComm(0x80+10);
		writeData('-');
		date=abs(date);
	}
	bai=date/100;
	shi=date%100/10;
	ge=date%10;

	writeData(0x30+bai);
	writeData(0x30+shi);
	writeData('.');
	writeData(0x30+ge);

}
void keyscan()
{
	uchar test,K;
	test=P1;
	if(test==0xfb)		   //1011
	{
	delay(4);
	led=1;
	test=P1;
	if(test==0xfb)	   //k1按下
	
	{
		while(P1!=0xff);
		led=0;
		K++;	   //k1=1
		while(1)
		{
			test=P1;
			if(test!=0xff)
		 {
			delay(5);
			led=1;
			test=P1;
			if(test!=0xff)
			{
				if(test==0xfb)
					K++;		  //k1=2

				switch(test)
				{
					case 0xfb:adjust();		//1011	 移动光标
							break;
					case 0xfd:inc();	   //1101
							break;
					case 0xfe:dec();		//1110
							break;
				}
						
						
				while(P1!=0xff);
				led=0;
		 	}
		 }
			if(K>3)
	        {	
				K=0;
				writeComm(0x0c);
				break;
	        }
			PID.setv=lshi*100+lge*10;
		}
		}
	}
}
void inc()
{
	delay(100);
	switch(flag)
	{
		case 1:lshi++; if(lshi>=10)
						lshi=0;
						writeData('0'+lshi);
						writeComm(0x10);
						break;
		case 2:lge++; if(lge>=10)lge=0;
						writeData('0'+lge);
						writeComm(0x10);
						break;
	}
}
void dec()
{
	delay(100);
	switch(flag)
	{
		case 1:lshi--; if(lshi<=-1)lshi=9;
						writeData('0'+lshi);
						writeComm(0x10);
						break;
		case 2:lge--; if(lge<=-1)lge=9;
						writeData('0'+lge);
						writeComm(0x10);
						break;
	}
}
void adjust()				 //0xfe	   k1
{


	delay(100);
	flag++;
	if(flag==3)
	flag=1;
	if(flag==1)
	{
	writeComm(0x80+3);
	writeComm(0x0f);			//光标闪烁
	 }
	 if(flag==2)
	{
		writeComm(0x80+4);
		writeComm(0x0f);	
	 }
}
没有更多推荐了,返回首页