C51单片机实践部分


本片摘录一些通用特殊代码

LED灯

  • 点亮一盏LED灯
    延时函数:这里使用程序延时,后面有更精确的采用计时器中断来延时,但是在代码的某些时候还是使用程序延时
void delay(unsigned long int x)
{
	while(x--);
}
  • 流水灯设计
    这里可以使用数组来储存每盏灯的状态,然后使用for循环显示。可自定义——因为数组里的每一个元素是对P1口及八个口对应的八盏灯的总状态的描述。
#include<reg51.h>
#define u8  unsigned char 
#define u32 unsigned long int

u8 buf[]={0x81,0x42,0x24,0x18,0x99,0x5A,0x3C,0xBD,0x7E,0xFF,0x01,0x02,0x04,0x08,
0x10,0x20,0x40,0x80};

void delay(u32 x)
{
	while(x--);
}							  
void main()
{
	u8 i;
	while(1)
	{
		for(i=0;i<sizeof(buf);i++)
		{
			P1=~buf[i];
			delay(1000);	
		}
	}
}

数码管

  • 一位静态数码管
    将数码管显示的数据编码出数码表
    显示部分和流水灯类似
// 共阳极数码管的数码表	
	u8 code codebuf[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; 
	
  • 两位静态数码管
    主要是出现了将多位数分位数显示
while( 1 )
	{
		for( i=0;i<100;i++ )
		{
			P2 = codebuf[i/10];						// 数码管显示0~99的数字
			P3 = codebuf[i%10];						// 数码管显示0~99的数字
			Delay_us( 50000 );						// 50000 us的时间
		}
	}
  • 两位动态数码管
    主要是利用人眼的延时显示实现动态
u8 DisBuf[2] = { 1,7 };								// 数码管显示数字17

void main( void )
{
	// 共阳极数码管的数码表	
	u8 code codebuf[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xbf,0xff}; 
	u8 i = 0;

	while( 1 )
	{
		for( i=0;i<2;i++ )												// 有2个数码管
		{
			P3 = 0xff;													// 关闭显示,消除鬼影
			P3 = (1<<i);												// 输出片选
			P2 = codebuf[DisBuf[i]]; 									// 根据缓冲区显示数据且数码管显示数字17
			Delay_us( 200 );											// 200 us的时间
		}
	}
}

  • 八位动态数码管
    和两位的类似,就是改动了DisBuf[8]
    要使数字变动起来,首先就是利用程序for循环变动DisBuf[8] 里面的值

按键

  • 独立按键

按键扫描

void ScanKey(void)
{
	if( 0 == Button1  )		return '+';	// 返回对数据执行的加数+
	if( 0 == Button2  )		return '-'; // 返回对数据执行的减数-
	return 0;
}

按键读取:其中包含按键判断,消除抖动,松手检测

u8 ReadKey(void)
{
	u8 tmp;

	tmp = ScanKey();						// 读取按键值
	if( 0 == tmp ) return 0;				// 判断是否有按键按下
	if( tmp!=ScanKey() ) return 0;			// 读回来的值是否与原来相同
	while( 0 != ScanKey()  );				// 读回来的按键为0,也就是说是松手检测
	return tmp;			
}

按键判断
使用switch语句

switch(ReadKey())
{
	// 0~99范围步进为1 相加1
	case '+':	Num = (Num+1)%99;				break;
	// 0~99范围步进为1 相减1
	case '-':	Num == 0 ? Num = 99: Num --;	break;	
}

数据拆分

void SegDisp( u8 Num )
{
	DisBuf[6] = Num/10;  						//
	DisBuf[7] = Num%10;							// 
}
  • 矩阵按键
    按键扫描
sbit K4 = P1^4; 					 								
sbit K5 = P1^5;
sbit K6 = P1^6;
sbit K7 = P1^7;




u8 ScanKey( void )
{
	P1 = ~(1<<0);								// 扫描第一行按键
	if( !K4 ) return '1';						// 返回值是字符1
	if( !K5 ) return '2';						// 返回值是字符2
	if( !K6 ) return '3';						// 返回值是字符3
	if( !K7 ) return 'A';						// 返回值是字符A

	P1 = ~(1<<1); 								// 扫描第二行按键
	if( !K4 ) return '4';						// 返回值是字符4
	if( !K5 ) return '5';						// 返回值是字符5
	if( !K6 ) return '6';					    // 返回值是字符6
	if( !K7 ) return 'B';					    // 返回值是字符B

	P1 = ~(1<<2);								// 扫描第三行按键
	if( !K4 ) return '7';						// 返回值是字符7
	if( !K5 ) return '8';						// 返回值是字符8
	if( !K6 ) return '9';						// 返回值是字符9
	if( !K7 ) return 'C';						// 返回值是字符C

	P1 = ~(1<<3); 								// 扫描第四行按键
	if( !K4 ) return '0';						// 返回值是字符0
	if( !K5 ) return 'D';						// 返回值是字符D
	if( !K6 ) return 'E';						// 返回值是字符E
	if( !K7 ) return 'F';					    // 返回值是字符F
	return 0;
}

void SegDisp( u8 Num )
{
	DisBuf[7] = Num;							
}

while( 1 )
	{
		tmp = ReadKey();						// 读取按键值
		if( tmp>='0'&&tmp<='9')					// 按下按键 字符 1~9
		{
			SegDisp(tmp - '0' );				// 数码管显示 1~9
		}

		if( tmp>='A'&&tmp<='F')					// 按下按键 字符 A~F
		{
			SegDisp(tmp - '7');			   		// 根据 ASSC 数码管显示 A~F
		}

中断

  • 外部中断

中断函数(写在主函数之外,中断发生就跳转到中断函数内执行中断函数内的程序,执行完又返回主函数)

反正就是配置寄存器

void Exit_Init(void)
{
	IT0 = 1;				// TCON.0 外部中断0:下降沿方法触发
	EX0 = 1;				// IE.0   外部中断0:中断允许
	EA  = 1;				// IE.7   全局中断 :允许中断
}

定时器

  • 定时器初始化
    配置TMOD,TH0和TL0,定时器0装载初值
    EA-中断总开关,ET0-中断溢出标志0,TR0-定时器0开关
// 定时器初始化
void time_init( void )
{
	TMOD = 0x01;								 	// 设置定时T0器工作方式1 	
  TH0 = (65536-2000)/256;							// 定时器T0高8位赋值													
	TL0 = (65536-2000)%256;						// 定时器T0低8位赋值	
	EA = 1;											// 开启T0总中断
	ET0 = 1;										// 开启计数/定时器T0中断
	TR0 = 1;										// 启动T0定时器
	
}
  • 定时器中断函数
    对TH0和TL0再次配置初值,然后在该函数内添加特定功能的程序
// 定时器中断函数
void time_0_handle( void ) interrupt 1
{
	TH0 = (65536-2000)/256;							// 定时器T0高8位赋值													
	TL0 = (65536-2000)%256;						// 定时器T0低8位赋值

	if( ++seconds <500 ) return;					// 判断是否达到1秒
	seconds = 0;									// 达到1秒,重新累计

    if( ++Sec<60 ) return;     					
        Sec = 0;                				
    if( ++Min<60 ) return;      				
        Min=0;                  				
    if( ++Hour<24 ) return;     				
        Hour = 0;    	
}

可调时钟

主要在于一个模式的调节
补充:这边有个三目运算符的使用
老师的代码很多地方会使用三目运算符

while( 1 )
	{
		switch( ReadKey() )
		{
			// 三种模式:时、分、秒
			case 'M':	Mode = (Mode+1)%4;		break;	
			// 时钟调整 增操作
			case '+':	
				if( 1 == Mode )						// 小时调整
				{
					Hour = (Hour+1)%24;				// 一天 24 小时		
				}
				else if ( 2== Mode )
				{
					Min = (Min+1)%60;				// 一小时60 分钟	
				}
				else if ( 3== Mode )
				{
					Sec = (Sec+1)%60;				// 一分钟 60 秒
				}
			break;
				
			// 时钟调整 减操作			
			case '-':		
				if( 1 == Mode )						// 小时调整
				{
					Hour == 0 ? Hour =23 : Hour--;	// 一天 24 小时		
				}
				else if ( 2== Mode )
				{
					Min == 0 ? Min =59 : Min--;		// 一小时60 分钟	
				}
				else if ( 3== Mode )
				{
					Sec == 0 ? Sec =59 : Sec--;		// 一分钟 60 秒
				}
			break;
		}

这边还有一段很特别的代码

// 定时器中断函数
void time_0_handle( void ) interrupt 1
{
	TH0 = (65536-2000)/256;							// 定时器T0高四位赋值													
	TL0 = (65536-2000)/256>>8;						// 定时器T0低四位赋值


//有个说法说这边的return可以提高代码稳定性
	if( ++seconds <500 ) return;					// 判断是否达到1秒
	seconds = 0;									// 达到1秒,重新累计

    if( ++Sec<60 ) return;     					
        Sec = 0;                				
    if( ++Min<60 ) return;      				
        Min=0;                  				
    if( ++Hour<24 ) return;     				
        Hour = 0;    	
}

1602驱动(比较复杂)

#include "reg52.h"					// 52寄存器库
#include<stdio.h>

sbit RS= P2^0 ;
sbit RW= P2^1 ;
sbit EN= P2^2 ;


/****************************************************************************
* 名称:Delay()
* 功能:延时函数
****************************************************************************/
void Delay( unsigned int i )
{
	while( i-- ) ;
}

/****************************************************************************
* 名称:WrOp()
* 功能:写命令函数
****************************************************************************/
void WrOp(unsigned char dat)
{
	RS= 0;		//全部清零
	RW= 0;
	P0= dat ;
	EN= 1;
	Delay(20);
	EN= 0;
}
/****************************************************************************
* 名称:WrDat()
* 功能:写数据函数
****************************************************************************/
void WrDat(unsigned char dat)	
{
	RS= 1;		//全部清零
	RW= 0;
	P0= dat ;
	EN= 1;
	Delay(20);
	EN= 0;
}
/****************************************************************************
* 名称:lcd_init()
* 功能:lcd初始化函数
****************************************************************************/
void lcd_init(void)
{
    //WrOp(0x01);	
	WrOp(0x38);			
	WrOp(0x06);			//光标加1
	WrOp(0x0F);			//开显示
	Delay(100);
}
/****************************************************************************
* 名称:DisText()
* 功能:显示文本函数
****************************************************************************/
void DisText(unsigned char addr,char *p)
{
	WrOp(addr);
	while( *p )WrDat(*(p++));
}

/****************************************************************************
 * 名称:main()
 * 功能:主程序
****************************************************************************/
void main( ) 
{		
	lcd_init( );
	DisText(0x80,"welcome to fjnu");
	DisText(0xc0+2,"14:15:20"); 
	while( 1 );
}

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。

  • 1602可调时钟
#include "reg52.h"					// 52寄存器库
#include<stdio.h>

bit disflash=0;

sbit RS= P2^0 ;
sbit RW= P2^1 ;
sbit EN= P2^2 ;

sbit key1= P1^0 ;
sbit key2= P1^1 ;
sbit key3= P1^2 ;

unsigned char mode=0;
unsigned int mSecond=0 ;					// 系统计时的毫秒和秒变量
unsigned char  Sec= 58,Min= 9,Hour= 16;	// 时分秒

/****************************************************************************
* 名称:Delay()
* 功能:延时函数
****************************************************************************/
void Delay( unsigned int i )
{
	while( i-- ) ;
}

/****************************************************************************
* 名称:WrOp()
* 功能:写命令函数
****************************************************************************/
void WrOp(unsigned char dat)
{
	RS= 0;		//全部清零
	RW= 0;
	P0= dat ;
	EN= 1;
	Delay(20);
	EN= 0;
}
/****************************************************************************
* 名称:WrDat()
* 功能:写数据函数
****************************************************************************/
void WrDat(unsigned char dat)	
{
	RS= 1;		//全部清零
	RW= 0;
	P0= dat ;
	EN= 1;
	Delay(20);
	EN= 0;
}
/****************************************************************************
* 名称:lcd_init()
* 功能:lcd初始化函数
****************************************************************************/
void lcd_init(void)
{
	WrOp(0x38);			
	WrOp(0x06);			//光标加1
	WrOp(0x0c);			//开显示
	Delay(100);
}
/****************************************************************************
* 名称:DisText()
* 功能:显示文本函数
****************************************************************************/
void DisText(unsigned char addr,char *p)
{
	WrOp(addr);
	while( *p )WrDat(*(p++));
}

/****************************************************
 函数:定时器0初始配置
 功能:1000uS中断一回,对毫秒变量和秒变量进行进位操作
*****************************************************/
void SysInit( void )
{
	TMOD= 0x01 ;     		// 设置定时器0为方式1
	TR0= 1 ;				// 启动定时器0进行记数
	ET0= 1 ;				// 开启定时器0中断功能
	EA= 1 ;					// 开启总中断
}

/****************************************************
 函数:定时器0中断程序
 功能:10000uS中断一回,对毫秒变量和秒变量进行进位操作
*****************************************************/
void Time0Int( void ) interrupt 1
{
	TL0= (65536-10000) ;		// 10毫秒定时预置值的低8位给TL0
	TH0= (65536-10000) >>8 ;	// 10毫秒定时预置值的高8位给TH0



	mSecond++ ;					// 对毫秒进行加1操作

	if( mSecond< 100 ) 			// 判断是否计满1秒
		return ;
	mSecond= 0;
	if(mode==0)
	{
		Sec++ ;
	}
	if( Sec< 60 ) 				// 判断是否计满60秒
		return ;
	Sec= 0 ;
	Min++ ;

	if( Min< 60 ) 				// 判断是否计满60分
		return ;
	Min= 0 ;
	Hour++ ;

	if( Hour>= 24 )
		Hour= 0;
}

/****************************************************
 函数:扫描当前按键, 返回用户按键值
*****************************************************/
unsigned char ScanKey( void )
{
	if( key1== 0 ) return  '1';		// 按键1
	if( key2== 0 ) return  '2';		// 按键2
	if( key3== 0 ) return  '3';	   	// 按键3
	return 0 ;		 			// 说明没有按键
}

/****************************************************
 函数:读一个按键值,如果没有按键返回为NULL
*****************************************************/
unsigned char ReadKey( void )
{
	unsigned char temp ;
	temp= ScanKey( ) ;				// 读取一个键值
	if( temp== 0 )
		return 0 ;				// 说明没有按键
	Delay( 1000 ) ;					// 等待10mS
	if( temp!= ScanKey( ) )			// 如果10mS后的值和前面的值不相等退出
		return 0 ;
	while( ScanKey( )!= 0 ) ;	// 等待用户放开按键

	return temp;					// 返回键值
}

/****************************************************************************
* 名称:Set_time()
* 功能:时间调整函数
****************************************************************************/
void Set_time(void)
{
	switch(mode)
	{		
		case 0:
			WrOp(0x0c);
			break;	
		case 1:
			WrOp(0x87);
			WrOp(0x0f);
			break;	
		case 2:
			WrOp(0x8a);
			WrOp(0x0f);
			break;
		case 3:
			WrOp(0x8d);
			WrOp(0x0f);
			break;
	}
	switch(ReadKey( ))
	{
		case '1':
			mode=(mode+1)%4 ;
			break;
		case '2':
			if(mode==1)Hour=(Hour+1)%24;
			if(mode==2)Min=(Min+1)%60;
			if(mode==3)Sec=(Sec+1)%60;
			disflash=1;
			break;	
		case '3':
			if( 1 == mode )						// ????
				{
					Hour == 0 ? Hour =23 : Hour--;	// ?? 24 ??		
				}
				else if ( 2== mode)
				{
					Min == 0 ? Min =59 : Min--;		// ???60 ??	
				}
				else if ( 3== mode )
				{
					Sec == 0 ? Sec =59 : Sec--;		// ??? 60 ?
				}
				disflash=1;
			break;
	}
}

/****************************************************************************
* 名称:main()
* 功能:主程序
****************************************************************************/
void main( ) 
{		
	unsigned char SecBak;
	char idata buf[20] ;
	SysInit( ) ;			// 系统初始化
	lcd_init( ); 
	while( 1 )
	{						
		Set_time( );
		if(disflash||SecBak!=Sec)
		{
			SecBak=Sec;
			disflash=0;
			sprintf( buf, "Time: %02d:%02d:%02d", (unsigned int)Hour, (unsigned int)Min, (unsigned int)Sec );
			DisText(0x80, buf ) ;  			// 0x80是第一行的开始位置
			DisText(0x80+0x40, "Welcome to FJNU!" ) ;		// 0xc0是第二行的开始位置
		}
	}
}

备注:这边使用了sprintf函数,将时分秒组合成一个字符串
这里还使用了disflash刷新标志,只有在数据变动的时候才刷新,使得这里的光标可以停留变动的地方

  • 传感器
    18B20 温度传感器
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值