当前位置:   article > 正文

51单片机嵌入式开发:21、STC89C52R控制抢答器+数码管+后台显示+LCD1602x显示_stc89c52 抢答

stc89c52 抢答

配套程序

配套程序


在这里插入图片描述

STC89C52R控制抢答器+数码管+后台显示+LCD1602x显示

1 概述

1.1 项目概述

该项目旨在利用STC89C52R单片机构建一个多功能抢答器显示系统,涵盖LCD1602x显示屏、数码管和后台数码显示器。通过串口通信,单片机能够与后台数码显示器进行数据交换和控制,实现更加灵活和多样化的显示功能。

1.2 项目组成部分

(1)STC89C52R单片机:
(2)LCD1602显示:
(3)数码管:
(4)后台数码显示器(通过串口通信):
(5)按键:
(6)Proteus:

在这里插入图片描述

1.3 功能描述

(1)LCD1602:
LCD1602显示屏用于展示文字信息,能够显示实时数据如日期、时间、温度等。
(2)数码管:
数码管用于呈现数字信息,例如计数器数值、计时器时间等。
后台数码显示器(通过串口通信):
借助串口通信,单片机与后台数码显示器相连,实现双向数据传输和控制,扩展显示功能。
(3)按键:
通过4个按键实现抢答器按钮功能。
(4)Proteus:
使用实物演示和Proteus仿真方式展示系统功能。

2 开发环境

2.1 支持设备

我们采用华晴51开发板、Keil开发工具和PROTEUS仿真软件。结合这三者,开发人员得以进行完整的嵌入式系统开发流程。他们可以利用Keil开发工具编写、编译和调试8051单片机程序,接着通过PROTEUS仿真软件验证程序正确性和系统功能。一旦验证通过,程序可下载至华晴51开发板进行实际硬件调试和测试,完成嵌入式系统的开发。这些工具的综合运用使得开发人员能够全面开发和验证嵌入式系统,提升开发效率、降低成本,并确保系统的稳定性和可靠性。
(1)华晴51开发板:
华晴51开发板是一款基于8051系列单片机的专用开发板,主要用于嵌入式系统的学习、开发和测试。该开发板拥有多样的外设接口,包括LED、按键、数码管、LCD显示屏、通信接口等,使用户能够轻松进行各种实验和项目开发。此外,华晴51开发板支持多种编程方式,如汇编语言、C语言等,适用于各类用户,无论是初学者还是专业开发人员。
(2)Keil开发工具:
Keil开发工具是一套专业的嵌入式系统开发工具,主要针对ARM和8051等处理器的嵌入式软件开发。其中,Keil C51是专为8051系列单片机设计的C语言集成开发环境,提供编译、调试、仿真等功能,使开发人员能够高效进行嵌入式软件开发。该工具配备了强大的调试功能,可帮助开发人员快速定位和解决程序中的问题,提升开发效率。
(3)PROTEUS仿真软件:
PROTEUS是一款被广泛应用于电子电路设计和仿真的软件。在嵌入式系统开发领域,PROTEUS通常用于对电路设计和单片机程序进行仿真,以验证系统功能、调试程序并检测潜在问题。该软件提供了丰富的元件库和仿真功能,使用户能够轻松搭建电路原理图、加载单片机程序,并进行实时仿真。

2.2 硬件电路

(1)STC89C52R单片机:

在这里插入图片描述

晶振使用11.0592Mhz

在这里插入图片描述

(2)LCD1602码表:

在这里插入图片描述

(3)数码管:

在这里插入图片描述

(4)后台数码显示器(通过串口通信):

在这里插入图片描述

(5)按键:
按键使用独立按键形式,P34 P35 P36 P37引脚

在这里插入图片描述

(6)实物与Proteus:

在这里插入图片描述

在这里插入图片描述

3 软件代码工程

//main.c文件

#include "includes.h"



/******************************************************************/
/*                    微秒延时函数  //10us                         */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{
	while(us--)
	{
	}
}

/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{
	while(Ms--)
	{
		delay_us(100);
	}
}





/*------------------------------------------------
                    主函数
------------------------------------------------*/


unsigned char pro_key_data = 0;

void main (void)
{
	char Test2[] = "                ";
	unsigned char databuf[4] = {0};
	//串口外设初始化
	sys_uart_init();
	//LCD1602显示屏初始化
	LCD_init();   
	sprintf(Test2,"Nunber:");
	LCD_write_strl(0,0,Test2,16);
	P1 = 0xFF;
    while (1)
    {
		//获取按键值
		pro_key_data = sys_key_single();
		
		
		
		if(pro_key_data)
		{
			//指示灯显示
			P1 &= ~(1<<(pro_key_data-1));
			
			//数码管显示
			sys_keynum_ledon(pro_key_data,0);
			
			
			//LCD1602显示
			LCD_write_com(0x80+7);
			lcd_number(pro_key_data);
		}
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

//includes.h文件

#ifndef __INCLUDES_H__
#define __INCLUDES_H__

//#include<reg52.h> 

#include<intrins.h> //汇编指令_nop_
#include<stdio.h> 	//标准输入输出

//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。

//8051 为每个机器周期 12 时钟
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。

//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。


//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"

//应用层头文件
//#include "c51_gpio.h"
#include "c51_ledtube.h"
#include "c51_key.h"
//#include "c51_timer.h"
//#include "c51_exit.h"
#include "c51_lcd1602.h"
//#include "c51_iic.h"
//#include "c51_tx1838.h"
#include "c51_uart.h"
//#include "c51_28byj48.h"
//#include "c51_ds1302.h"

extern unsigned char pro_key_data;



extern void delay_us(unsigned int us);//delay us;
extern void delay_ms(unsigned int Ms);//delay Ms;




#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

//c51_ledtube.c文件

#include "includes.h"

 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
//unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F

code unsigned char ledmap[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x40,0x80};


///********************************************************
//函数名称:sys_ledtube_on1
//函数功能:点亮一个数码管全为亮起来
//入口参数:
//出口参数:
//修    改:
//内    容:
//********************************************************/
//void sys_ledtube_on1(void)
//{
//	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
//	P0=0xFF;//取显示数据,段码
//	P2=0;  	//取位码
//}

///********************************************************
//函数名称:sys_ledtube_on2
//函数功能:显示一组数据
//入口参数:
//出口参数:
//修    改:
//内    容:
//********************************************************/
//static unsigned char ledtube_cnt = 0;

//void sys_ledtube_on2(void)
//{
//	ledtube_cnt++;
//	if(ledtube_cnt>7)
//	{
//		ledtube_cnt = 0;
//	}
//	P0 = 0x00;				//防止切换数码管瞬间有虚影出现
//	P2 = 0x00;
//	P0 = ledmap[ledtube_cnt];	//取显示数据,段码
//	P2 = ledtube_cnt;  		//取位码
//	
//	//根据人眼适应虚影缓冲时间为50ms左右
//	//我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
//	delay(100); 			
//}


///********************************************************
//函数名称:sys_keynum_ledon
//函数功能:显示按键数值
//入口参数:按键数值
//出口参数:
//修    改:
//内    容:
//********************************************************/
void sys_keynum_ledon(unsigned char num,unsigned char pn)
{
	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
	P0 = 0x00;		//防止切换数码管瞬间有虚影出现
	P2 = pn;  		//取位码
	P0 = ledmap[num];	//取显示数据,段码
	delay_ms(1);
	
	
	P2 = 7;  		//取位码
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

//c51_ledtube.h文件

#ifndef __C51_LEDTUBE_H__
#define __C51_LEDTUBE_H__


//extern unsigned char const EL[];

//extern void sys_ledtube_on1(void);
//extern void sys_ledtube_on2(void);

extern void sys_keynum_ledon(unsigned char num,unsigned char pn);


#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

//c51_uart.c文件

#include "includes.h"



/*-----------------------------------------------
  名称:串口通信
  内容:连接好串口或者usb转串口至电脑,下载该程序,打开电源
        打开串口调试程序,将波特率设置为9600,无奇偶校验
        晶振11.0592MHz,发送和接收使用的格式相同,如都使用
        字符型格式,在发送框输入 hello,I Love MCU ,在接
        收框中同样可以看到相同字符,说明设置和通信正确
------------------------------------------------*/
                    


/******************************************************************/
void sys_uart_init(void)
{


	SCON  = 0x50;		        /* SCON: 模式 1, 8-bit UART, 使能接收         */
	TMOD |= 0x20;               /* TMOD: timer 1, mode 2, 8-bit reload        */
	TH1   = 0xFD;               /* TH1:  reload value for 9600 baud @ 11.0592MHz   */
	TR1   = 1;                  /* TR1:  timer 1 run                          */
	EA    = 1;                  /*打开总中断*/
	//ES    = 1;                  /*打开串口中断*///当使用串口协议通讯时可以使用此型号中断

}


void Uart_SendChar(unsigned char  dat)
{
    SBUF = dat; 
    while(!TI); 
    TI = 0; 
}
 
char putchar(char c)//重定向
{
    Uart_SendChar(c);
    return c;

}

/******************************************************************/
/*                  串口中断程序                                  */
/******************************************************************/


static unsigned char uart_temp = 0;          //定义临时变量 
static unsigned char uart_cnt = 0;          //定义临时变量 


void UART_isr(void) interrupt 4 //串行中断服务程序
{
	if(RI)                        //判断是接收中断产生
	{
		RI=0;                      //标志位清零
		uart_temp=SBUF;                 //读入缓冲区的值
		if(uart_cnt==0)
		{
			if(0x02 == uart_temp)
			{
				uart_cnt = 1;
			}
			else
			{
				uart_cnt = 0;
			}
		}
		else if(uart_cnt==1)
		{
			if(0x05 == uart_temp)
			{
				uart_cnt = 2;
			}
			else
			{
				uart_cnt = 0;
			}
		}
		else if(uart_cnt==2)
		{
			uart_cnt = 0;
			//P1=uart_temp;                   //把值输出到P1口,用于观察
			SBUF=uart_temp;                 //把接收到的值再发回电脑端
		}
		else
		{
			uart_cnt = 0;
		}
	}
	if(TI)                        //如果是发送标志位,清零
	{
		TI=0;
	}
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

//c51_uart.h文件

#ifndef __C51_UART_H__
#define __C51_UART_H__


extern void Uart_SendChar(unsigned char  dat);
extern char putchar(char c);//重定向

extern void sys_uart_init(void);
extern void UART_isr(void);


#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

//c51_lcd1602.c文件

#include "includes.h"

#include <string.h>

/******************************************************************/
/*                   写入命令函数                                 */
/******************************************************************/
void LCD_write_com(unsigned char com) 
{  
	RS_CLR; 
	RW_CLR; 
	EN_SET; 
	P0 = com; 
	delay_us(5); 
	EN_CLR;
}

/******************************************************************/
/*                   写入数据函数                                 */
/******************************************************************/
void LCD_write_Data(unsigned char Data) 
{ 
	RS_SET; 
	RW_CLR; 
	EN_SET; 
	P0 = Data; 
	delay_us(5); 
	EN_CLR;
}


/****************************************
函数功能:LCD显示数字0-9
*****************************************/
void lcd_number(unsigned int number)
{
	int num[10]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
	switch(number)
	{
		case 0:LCD_write_Data(num[0]);
		break;
		case 1:LCD_write_Data(num[1]);
		break;
		case 2:LCD_write_Data(num[2]);
		break;
		case 3:LCD_write_Data(num[3]);
		break;
		case 4:LCD_write_Data(num[4]);
		break;
		case 5:LCD_write_Data(num[5]);
		break;
		case 6:LCD_write_Data(num[6]);
		break;
		case 7:LCD_write_Data(num[7]);
		break;
		case 8:LCD_write_Data(num[8]);
		break;
		case 9:LCD_write_Data(num[9]);
		break;
	}
}

/******************************************************************/
/*                   初始化函数                                   */
/******************************************************************/
void LCD_init(void) 
{
	LCD_write_com(0x38);    /*显示模式设置*/ 
	delay_ms(5); 
	LCD_write_com(0x38); 
	delay_ms(5); 
	LCD_write_com(0x38); 
	delay_ms(5); 
	LCD_write_com(0x38);  
	LCD_write_com(0x08);    /*显示关闭*/ 
	LCD_write_com(0x01);    /*显示清屏*/ 
	LCD_write_com(0x06);    /*显示光标移动设置*/ 
	delay_ms(5); 
	LCD_write_com(0x0C);    /*显示开及光标设置*/
}


 
/******************************************************************/
/*                   写入字符串函数                                */
/*      X:第几列 Y:第几行  *s字符串为空时跳出                      */
/******************************************************************/
void LCD_write_strl(unsigned char x,unsigned char y,unsigned char *s,unsigned length) 
{     
	unsigned char cnt = 0;
	//LCD_write_com(0x01);    /*显示清屏*/ 
	
	if (y == 0) 
	{     
		LCD_write_com(0x80 + x);     
	}
	else 
	{     
		LCD_write_com(0xC0 + x);     
	}
       
	while(length--)
	{     
		LCD_write_Data( *s);     
		s ++;
		cnt++;
		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109

//c51_lcd1602.h文件

#ifndef __C51_LCD1602_H__
#define __C51_LCD1602_H__



#include "STC89C5xRC_RDP.h"


//定义宏定义

sbit RS = P2^4;   //定义端口 
sbit RW = P2^5;
sbit EN = P2^6;

#define RS_CLR RS=0 
#define RS_SET RS=1
#define RW_CLR RW=0 
#define RW_SET RW=1 
#define EN_CLR EN=0
#define EN_SET EN=1


extern void LCD_write_com(unsigned char com) ;
extern void LCD_write_Data(unsigned char Data) ;
extern void lcd_number(unsigned int number);
extern void LCD_init(void) ;
extern void LCD_write_strl(unsigned char x,unsigned char y,unsigned char *s,unsigned length) ;




#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

//c51_key.c文件

#include "includes.h"

sbit key1=P3^7;//定义按键位置 需要切换到独立按键模式 
sbit key2=P3^6;
sbit key3=P3^5;
sbit key4=P3^4;
bit Flag = 0;
unsigned char key_num = 0;

/******************************************************************/
/*                    主函数                                      */
/******************************************************************/
unsigned char sys_key_single(void)
{
	  if(!Flag)           //执行一次就停止了 先检测到的相应 复位后有效
      {
		  if(!key1)     {P1=0xFE;Flag=1;key_num=1;printf("The key_num :Number 1;\r\n");}//
		  else if(!key2){P1=0xFD;Flag=1;key_num=2;printf("The key_num :Number 2;\r\n");}//
		  else if(!key3){P1=0xFB;Flag=1;key_num=3;printf("The key_num :Number 3;\r\n");}//
		  else if(!key4){P1=0xF7;Flag=1;key_num=4;printf("The key_num :Number 4;\r\n");}//
		  else 
		  {
			key_num=0;
		  }
		  
		  
		//串口后台打印数字
      }
	  return key_num;
}

//如果有干扰请加去抖程序
//红外接收头部分用黑色物质遮光,防止干扰按键
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

//c51_key.h文件

#ifndef __C51_KEY_H__
#define __C51_KEY_H__


extern unsigned char sys_key_single(void);  //键盘扫描函数,使用行列反转扫描法

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

配套程序

4 演示Proteus仿真

在这里插入图片描述

5 总结

STC89C52R控制抢答器+数码管+后台显示+LCD1602x显示具有以下价值和优势:
1.
功能丰富性:整合抢答器、数码管、后台显示和LCD1602x显示功能,实现多样化的信息展示和控制功能。
2. 灵活性:通过STC89C52R控制,系统具有灵活的数据交换和控制能力,可根据需求定制显示内容和功能。
3. 用户体验:提供直观的数码显示和LCD1602x显示,增强用户交互体验,使信息更加清晰和易读。
4. 系统稳定性:采用STC89C52R作为控制核心,系统稳定可靠,保证长时间稳定运行。
5. 开发效率:整合多种显示功能和控制模块,简化开发流程,提高开发效率和系统集成度。
6. 教育和培训:适用于教育和培训领域,帮助学习者理解嵌入式系统开发和控制原理。
7. 应用广泛:可用于各类竞赛、培训、演示等活动中,扩展了系统应用领域和功能范围。
这些优势使得STC89C52R控制的抢答器与数码管、后台显示和LCD1602x显示系统成为一款具有实用性和创新性的嵌入式系统,能够满足多样化的需求并提升用户体验。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/1004891
推荐阅读
相关标签
  

闽ICP备14008679号