C51相关实验

news2024/11/29 23:23:19

C51相关实验

  • LED (P2 / 0~7)
  • 蜂鸣器 (P2^5)
  • 数码管 (P0 0~7 段 ,P2 2~4 位)
  • 独立按键 (P3^1 P3^0 P3^2 P3^3)
  • 直流电机 (J47 5v 01~04)
  • 综合实验
  • 矩阵按键 (P1组 0~7)
  • LED点阵

LED (P2 / 0~7)

//功能:1.让开发板的LED全亮,2,点亮某一个LED,3.让LED3以5Hz的频率闪动

#include "reg52.h"

#define LED		P2
sbit led1 = LED^1;


void main(void)
{
	LED = 0xff;//LED全灭
    led1 = 0;
	while(1)//保持应用程序不退出
	{

	}
}

LED 输出端是高电平 所以要让LED点亮只需要让MCU输出低电平即可,内置引脚是P2,所以要让哪个亮只需要让哪个引脚为0 例子:LED^3=0;让第三个LED亮起
在这里插入图片描述

蜂鸣器 (P2^5)

对于无源蜂鸣器,通过改变脉冲频率就可以调节蜂鸣器的音调,产生各种不同的音色,音调的声音。
对于无源蜂鸣器,通过改变脉冲占空比(高电平占用脉冲周期的百分比)就可以改变蜂鸣器声音的大小。

在这里插入图片描述

//功能:让蜂鸣器以100HZ频率,50%音量,响10s
#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;

//定义BEEP的控制引脚
sbit BEEP	=	P2^5;//申明蜂鸣器的控制引脚

//以秒为单位的延时器
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						

//u8frequency:蜂鸣器的工作频率,范围2Hz-1KHz
//u8duty:蜂鸣器脉冲占空比,范围0-100;
//times:以秒为单位的时间,范围大于0
void Beep(u8 u8frequency,u8 u8duty,u8 times)
{
	u16 i;
	u16 period ,on_time ,off_time;
	
//参数校验 防止越界
	if(u8frequency>1000) u8frequency = 1000;
	if(u8frequency==0) u8frequency = 10;

	if(u8duty>100)u8duty = 100;
	if(u8duty == 0)u8duty = 1;

	if(times == 0)times = 1;

	 period =  1000/u8frequency;//以毫秒为单位的周期
	 on_time = period/100*u8duty;	//计算高电平的时间,以毫秒为单位 1周期内高电平
	 off_time = period - on_time;
	for(i=0;i<u8frequency*times;i++)//遍历10s内所有的脉冲
	{
		 BEEP = 1;
		 delay_ms(on_time);
		 BEEP = 0;
		 delay_ms(off_time);	
	}
}

void main()
{
		Beep(100,50,10);
	   while(1)	//保持应用程序不退出
	   {  

	   }
}

多频率

//功能:/*	  多频率声音输出:
//需求:蜂鸣器应能够输出不同频率的声音。
//实现:定义一个频率数组u16 frequencies[] = {1000, 1500, 2000, 2500}包含若干个频率值。程序会循环遍历这些频率,产生相应的声音。
#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;

//定义BEEP的控制引脚
sbit BEEP	=	P2^5;//申明蜂鸣器的控制引脚

//u16Frequency:蜂鸣器的工作频率,范围2Hz-5KHz
//u8duty:蜂鸣器脉冲占空比,范围0-100;
//u16durations:以秒为单位的时间,范围大于0
void Beep(u16 u16Frequency,u8 u8duty,u16 u16durations);

//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						

//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}

void main()
{
	u16	u16Freqs[] = {1000,1500,2000,3000};//定义一个频率数组
	u8	u8duty = 50;
	u8 i;
	u8 num = sizeof(u16Freqs)/sizeof(u16Freqs[0]);

	for(i=0;i<num;i++)
	{
		Beep(u16Freqs[i],u8duty,2);	
		delay_ms(1000);//每次蜂鸣器在切换频率之间,停1s
	}

	while(1)	//保持应用程序不退出
	{  
	
	}
}

void Beep(u16 u16Frequency,u8 u8duty,u16 u16durations)
{
	u16 i;
	u32 period ,on_time ,off_time;
	
//参数校验
	if(u16Frequency>5000) u16Frequency = 5000;
	if(u16Frequency==0) u16Frequency = 1000;

	if(u8duty>100)u8duty = 100;
	if(u8duty == 0)u8duty = 1;

	if(u16durations == 0)u16durations = 1;

	 period =  1000000/u16Frequency;//以微秒为单位的脉冲周期
	 on_time = period/100*u8duty;	//计算高电平的时间,以微秒为单位
	 off_time = period - on_time;
	for(i=0;i<u16Frequency*u16durations;i++)//遍历所有的脉冲
	{
		 BEEP = 0;
		 delay_10us(on_time/10);//延时是以10us为单位的延时,这里需要除10
		 BEEP = 1;
		 delay_10us(off_time/10);	
	}
}

数码管 (P0 0~7 段 ,P2 2~4 位)

数码管是一种半导体发光器件,其基本单元是发光二极管。
按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管。
共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数 码管。
共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数 码管。

在这里插入图片描述

共阴或者共阳,a-g+小数点总共8段对应8个引脚,下面是对应显示,a-g从低到高
在这里插入图片描述

LED数码管显示器工作方式有两种:静态显示方式和动态显示方式。
静态显示的特点:每个数码管的段选必须接一个8位数据线来保持显示的字形码。
静态显示:也就是不需要刷新显示写在while外面,反之写在里面

在这里插入图片描述

1.定义数码管的端口的IO。#define SMG_1 P0
2.定义数码管编码数据 u8 smg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//数码管显示
#include "reg52.h"

// 数码管控制引脚别名
#define SMG P0

// 毫秒延时函数
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 123; j++); // 123 是一个经验值,根据实际情况调整
    }
}

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

// 0-F 共阴八段数码管编码
u8 smg_code[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 
                 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

// 数码管位选引脚
sbit SMG_22 = P2^2; // 第一个数码管控制位
sbit SMG_23 = P2^3; // 第二个数码管控制位
sbit SMG_24 = P2^4; // 第三个数码管控制位

void SMG_display(void)
{
	  u8 i;
	   for(i=0;i<8;i++)
	   {
	   		//从高到低
	   		//SMG_22=i%2;
			//SMG_23=(i/2)%2;
			//SMG_24=i/4;
			//从低到高
			SMG_22=!(i%2);
			SMG_23=!((i/2)%2);
			SMG_24=!(i/4);
	   		SMG=smg_code[i];
			delay_ms(1);
			SMG = 0;//消影
	   }
}
void main(void) {
    u16 i;
    while(1) {
       SMG_display();
    }
}

在这里插入图片描述

独立按键 (P3^1 P3^0 P3^2 P3^3)

在这里插入图片描述

从上图中可以看出,4个独立按键的控制管脚连接到51单片机的P3.0-P3.3 脚上。其中K1连接在P3.1上,K2连接在P3.0上,K3连接在P3.2上,K4连接 在P3.3上。4个按键另一端全部连接在GND,当按键按下后,对应IO口即为低 电平。
在这里插入图片描述
由于机械按键大概有10ms 的误差

按键控制LED灯亮


//独立按键 按键1LED1亮
#include "reg52.h"

//毫秒延时函数
void delay_ms(unsigned int ms) {
	unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 123; j++); // 123 是一个经验值,可以根据实际情况调整
    }
}
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//定义独立按键引脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//定义LED灯引脚
sbit LED1=P2^0;
sbit LED2=P2^1;
sbit LED3=P2^2;
sbit LED4=P2^3;
//独立按键控制led灯
void key_contralled()
{
	if(KEY1==0)
	{  	
		delay_ms(10);//消抖
		if(KEY1==0)	 LED1=!LED1;
		
		delay_ms(200);
	}
	if(KEY2==0)
	{
		delay_ms(10);//消抖
	 	if(KEY2==0)	LED2=!LED2;
		delay_ms(200);
	}
	if(KEY3==0)
	{
		delay_ms(10);//消抖
	 	if(KEY3==0)	LED3=!LED3;
		delay_ms(200);
	}
	if(KEY4==0)
	{
		delay_ms(10);//消抖
	 	if(KEY4	==0)	LED4=!LED4;
		delay_ms(200);
	}
}
void main(void)
{
	
	while(1)//保持程序不退出
	{
		key_contralled();	
	}
}

直流电机 (J47 5v 01~04)

原理图:默认J47 接电源 P1 ^ 0~P1 ^ 3 对应OUT1~OUT4 ,当MCU输出端为高电平时直流电机不工作,低电平时直流电机开始工作,由于内部工作时非门逻辑,所以在用代码实现的时候也就是 高电平即1开始工作,反之0不工作
在这里插入图片描述

//功能:控制直流电机运行5s后停
//接线:J47的1脚----直流电机任意一个引脚
//		J47的2脚----直流电机的另外一引脚

#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;


//定义直流电机的控制引脚
sbit DC_MOTOR	=	P1^0;

//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						

//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}


void MOTOR_Run(u8 u8duration);

void main()
{
	DC_MOTOR = 0;//关闭直流电机
	MOTOR_Run(5);
	while(1)	//保持应用程序不退出
	{  

	}
}

void MOTOR_Run(u8 u8duration)
{
	DC_MOTOR = 1;//打开直流电机
	delay_ms(1000*u8duration);
	DC_MOTOR = 0;//关闭直流电机
}

综合实验

 //功能:
/*
● 增加预置时间和计数值的变量。
● 数码管的前4位显示预置时间,后4位显示计数值。
● 按键检测和预置时间调整功能。
● 直流电机运行和停止的逻辑。
● k1加
● k2减
● k3,开始计数,直流机电要转,到计数等于预值时,直流电机停转,蜂鸣器响1s
● k4,暂停/恢复
预值范围10--40

分析:
1.数码管显示模块  			(8+3)IO			   output
2.按键扫描模块				4IO	  				   input
3.定时器模块
4.功能模块(直流电机+蜂鸣器)		 2IO		   output
*/

#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;


//定义直流电机的控制引脚
sbit DC_MOTOR	=	P1^0;

//定义BEEP的控制引脚
sbit BEEP	=	P2^5;//申明蜂鸣器的控制引脚

//u8frequency:蜂鸣器的工作频率,范围2Hz-1KHz
//u8duty:蜂鸣器脉冲占空比,范围0-100;
//times:以秒为单位的时间,范围大于0
void Beep(u8 u8frequency,u8 u8duty,u8 times);

//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						

//0-F共阴八段数码管编码
u8 smg_code[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//定义数码管段选引脚
#define SMG		P0

//定义数码管的位选引脚
sbit SMG_22 = P2^2;
sbit SMG_23 = P2^3;
sbit SMG_24 = P2^4;

//u8code表示8位数码管要显示的编码
void SMG_Display(u8 u8code[]);

//定义LED的控制引脚
sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;

//定义独立按键的控制引脚
sbit KEY1 = P3^1;
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

//定义键值
#define KEY_UNPRESS	0
#define KEY1_PRESS	1
#define KEY2_PRESS	2
#define KEY3_PRESS	3
#define KEY4_PRESS	4

u8 Key_Scan(void);//返回被按下的独立按键值


//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}


#define PRESEC_MIN	10
#define PRESEC_MAX 	40

static u8 g_u8PreSec	=	PRESEC_MIN;//预值时间
static u8 g_u8CurSec	=	0;			//计数时间

void main()
{
	u8 u8code[8] = {0};
	u8 u8key = KEY_UNPRESS;
	u8 i = 0;//秒时间计数器

	DC_MOTOR = 0;//关闭直流电机

	while(1)	//保持应用程序不退出
	{
		//按键扫描
		u8key = Key_Scan();
		switch(u8key)
		{
			case KEY1_PRESS:		//+
				if(g_u8PreSec<PRESEC_MAX)
				{
					g_u8PreSec++;
				}
				break;

			case KEY2_PRESS:		//-
				if(g_u8PreSec>PRESEC_MIN)
				{
					g_u8PreSec--;
				}
				break;			 

			case KEY3_PRESS:		//start
				DC_MOTOR = 1;		
				break;

			case KEY4_PRESS:		//pause+resume
			   DC_MOTOR = !DC_MOTOR;

				break;
			 
			 default:
			 	break;	
		}

		
		//定时器,每秒更新一次
		if(i == 100)
		{
			i = 0;
			if(DC_MOTOR)
			{
			  g_u8CurSec++;
			}
		}
		
		//功能模块,直流电机及蜂鸣器
		if((g_u8CurSec == g_u8PreSec) && DC_MOTOR)
		{
			 DC_MOTOR = 0;
			 Beep(3000,80,1);
			 g_u8CurSec = 0;
		}

		
		//数码管显示  
		 u8code[2] = smg_code[g_u8PreSec/10];//预值时间的十位
		 u8code[3] = smg_code[g_u8PreSec%10];//预值时间的个位

		 u8code[6] = smg_code[g_u8CurSec/10];//计数时间的十位
		 u8code[7] = smg_code[g_u8CurSec%10];//计数时间的个位

		SMG_Display(u8code);
		delay_ms(1);
		i++;
	}
}



void Beep(u8 u8frequency,u8 u8duty,u8 times)
{
	u16 i;
	u16 period ,on_time ,off_time;
	
//参数校验
	if(u8frequency>1000) u8frequency = 1000;
	if(u8frequency==0) u8frequency = 10;

	if(u8duty>100)u8duty = 100;
	if(u8duty == 0)u8duty = 1;

	if(times == 0)times = 1;

	 period =  1000/u8frequency;//以毫秒为单位的周期
	 on_time = period/100*u8duty;	//计算高电平的时间,以毫秒为单位
	 off_time = period - on_time;
	for(i=0;i<u8frequency*times;i++)//遍历10s内所有的脉冲
	{
		 BEEP = 1;
		 delay_ms(on_time);
		 BEEP = 0;
		 delay_ms(off_time);	
	}
}

void SMG_Display(u8 u8code[])
{
	//u8code放的是当前每位数码管的段码
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)
		{
			case 0:	SMG_24 = 1;SMG_23 = 1;SMG_22 = 1;break;//7位
			case 1:	SMG_24 = 1;SMG_23 = 1;SMG_22 = 0;break;//6位
			case 2:	SMG_24 = 1;SMG_23 = 0;SMG_22 = 1;break;//5位
			case 3:	SMG_24 = 1;SMG_23 = 0;SMG_22 = 0;break;//4位
			case 4:	SMG_24 = 0;SMG_23 = 1;SMG_22 = 1;break;//3位
			case 5:	SMG_24 = 0;SMG_23 = 1;SMG_22 = 0;break;//2位
			case 6:	SMG_24 = 0;SMG_23 = 0;SMG_22 = 1;break;//1位
			case 7:	SMG_24 = 0;SMG_23 = 0;SMG_22 = 0;break;//0位
			default:break;
		}
		//数码管段选
		SMG = u8code[i];
		delay_ms(1);//当前位的数码管显示保持时间
		SMG = 0;//消影
	}
}

u8 Key_Scan(void)//返回被按下的独立按键值
{
	u8 u8key = 	KEY_UNPRESS;
	
	if(KEY1 == 0)
	{
		//消抖
		delay_ms(10);
		if(KEY1 == 0)//再次确认状态
		{
			 u8key = KEY1_PRESS;
			
		}
	}

	if(KEY2 == 0)
	{
		//消抖
		delay_ms(10);
		if(KEY2 == 0)
		{
			 u8key = KEY2_PRESS;
		}
	}

	if(KEY3 == 0)
	{
		//消抖
		delay_ms(10);
		if(KEY3 == 0)//再次确认状态
		{
			 u8key = KEY3_PRESS;
		}
	}	

	if(KEY4 == 0)
	{
		//消抖
		delay_ms(10);
		if(KEY4 == 0)//再次确认状态
		{
			 u8key = KEY4_PRESS;
		}
	}
	while((KEY1==0)||(KEY2==0)||(KEY3==0)||(KEY4==0));//防抖防止按键触发多次未弹起
	return u8key;

}

注意:在这里面使用的计时器是以为一次循环大概时间,凑够1s来实现1s刷新数码管,数码管的数显时间大概在10ms

矩阵按键 (P1组 0~7)

在这里插入图片描述
实现原理:按钮按下后当前行列电平都为低电平,从而判断出哪个按钮被按下了,那么找出当前按下按钮,就可以设置P1 ^7~4 前4个为低电平(0),后四个为高电平P1 ^3~0(F),当前引脚P1不等于0F 那么就证明这一列有被按下的按键,然后在翻转F0 不等于这个证明哪行有被按下的

//功能:以列扫描的方式实现矩阵按键,并在数码管上显示键值


#include "reg52.h"

typedef unsigned int 	u16;
typedef unsigned char 	u8;
typedef unsigned long 	u32;


//以毫秒为单位的延时
void delay_ms(unsigned int ms){
		 unsigned int i,j;
		 for(i=ms;i>0;i--)
		 	for(j=123;j>0;j--);
}						

//0-F共阴八段数码管编码
u8 smg_code[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//定义数码管段选引脚
#define SMG		P0

//定义数码管的位选引脚
sbit SMG_22 = P2^2;
sbit SMG_23 = P2^3;
sbit SMG_24 = P2^4;

//u8code表示8位数码管要显示的编码
void SMG_Display(u8 u8code[]);


//定义矩阵按键的控制引脚
#define KEY_PORT	P1


//定义键值
#define KEY_UNPRESS	0
#define KEY1_PRESS	1
#define KEY2_PRESS	2
#define KEY3_PRESS	3
#define KEY4_PRESS	4
#define KEY5_PRESS	5
#define KEY6_PRESS	6
#define KEY7_PRESS	7
#define KEY8_PRESS	8
#define KEY9_PRESS	9
#define KEY10_PRESS	10
#define KEY11_PRESS	11
#define KEY12_PRESS	12
#define KEY13_PRESS	13
#define KEY14_PRESS	14
#define KEY15_PRESS	15
#define KEY16_PRESS	16

u8 Key_Scan(void);//返回被按下的独立按键值

u8 Key_ColScan(void);//返回被按下的矩阵按键值


//以10微秒为单位的延时
void delay_10us(u16 ten_us)
{
	while(ten_us--);
}


void MOTOR_Run(u8 u8duration);

#define PRESEC_MIN	10
#define PRESEC_MAX 	40

static u8 g_u8PreSec	=	PRESEC_MIN;//预值时间
static u8 g_u8CurSec	=	0;			//计数时间

void main()
{
	u8 u8code[8] = {0};
	u8 u8key = KEY_UNPRESS;


	while(1)	//保持应用程序不退出
	{
		//按键扫描
		u8key = Key_ColScan();
		if(u8key!=KEY_UNPRESS)
		{
			  		//数码管显示  
			 u8code[6] = smg_code[u8key/10];//十位
			 u8code[7] = smg_code[u8key%10];//个位
		}

		SMG_Display(u8code);
		delay_ms(1);

	}
}

void SMG_Display(u8 u8code[])
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)
		{
			case 0:	SMG_24 = 1;SMG_23 = 1;SMG_22 = 1;break;//7位
			case 1:	SMG_24 = 1;SMG_23 = 1;SMG_22 = 0;break;//6位
			case 2:	SMG_24 = 1;SMG_23 = 0;SMG_22 = 1;break;//5位
			case 3:	SMG_24 = 1;SMG_23 = 0;SMG_22 = 0;break;//4位
			case 4:	SMG_24 = 0;SMG_23 = 1;SMG_22 = 1;break;//3位
			case 5:	SMG_24 = 0;SMG_23 = 1;SMG_22 = 0;break;//2位
			case 6:	SMG_24 = 0;SMG_23 = 0;SMG_22 = 1;break;//1位
			case 7:	SMG_24 = 0;SMG_23 = 0;SMG_22 = 0;break;//0位
			default:break;
		}
		//数码管段选
		SMG = u8code[i];
		delay_ms(1);//当前位的数码管显示保持时间
		SMG = 0;//消影
	}
}

//这是通过一个个扫描实现的
u8 Key_ColScan(void)//返回被按下的矩阵按键值
{
	u8 u8key = KEY_UNPRESS;
	//扫描第一列 设置11110111  从高到低 P17-P10
	KEY_PORT = 0xF7;		//将矩阵按键第一列变为独立按键且没有按下的状态
	if(KEY_PORT!=0xF7)		//第一列有按键状态变化
	{
		delay_ms(10);	//消抖
		if(KEY_PORT!=0xF7)	//再次确认
		{
			switch(KEY_PORT)
			{
				case 0x77:	u8key = KEY1_PRESS;	break;
				case 0xb7:	u8key = KEY5_PRESS;	break;
				case 0xd7:	u8key = KEY9_PRESS;	break;
				case 0xe7:	u8key = KEY13_PRESS;	break;
				default:
					break;
			}
		}
	}
	while(KEY_PORT!=0xF7);		//等待第一列所有按键弹起
		//扫描第二列
	KEY_PORT = 0xFb;		//将矩阵按键第2列变为独立按键且没有按下的状态
	if(KEY_PORT!=0xFb)		//第2列有按键状态变化
	{
		delay_ms(10);	//消抖
		if(KEY_PORT!=0xFb)	//再次确认
		{
			switch(KEY_PORT)
			{
				case 0x7b:	u8key = KEY2_PRESS;	break;
				case 0xbb:	u8key = KEY6_PRESS;	break;
				case 0xdb:	u8key = KEY10_PRESS;	break;
				case 0xeb:	u8key = KEY14_PRESS;	break;
				default:
					break;
			}
		}
	}
	while(KEY_PORT!=0xFb);		//等待第2列所有按键弹起

		//扫描第3列
	KEY_PORT = 0xFd;		//将矩阵按键第3列变为独立按键且没有按下的状态
	if(KEY_PORT!=0xFd)		//第3列有按键状态变化
	{
		delay_ms(10);	//消抖
		if(KEY_PORT!=0xFd)	//再次确认
		{
			switch(KEY_PORT)
			{
				case 0x7d:	u8key = KEY3_PRESS;	break;
				case 0xbd:	u8key = KEY7_PRESS;	break;
				case 0xdd:	u8key = KEY11_PRESS;	break;
				case 0xed:	u8key = KEY15_PRESS;	break;
				default:
					break;
			}
		}
	}
	while(KEY_PORT!=0xFd);		//等待第3列所有按键弹起


		//扫描第4列
	KEY_PORT = 0xFe;		//将矩阵按键第4列变为独立按键且没有按下的状态
	if(KEY_PORT!=0xFe)		//第4列有按键状态变化
	{
		delay_ms(10);	//消抖
		if(KEY_PORT!=0xFe)	//再次确认
		{
			switch(KEY_PORT)
			{
				case 0x7e:	u8key = KEY4_PRESS;	break;
				case 0xbe:	u8key = KEY8_PRESS;	break;
				case 0xde:	u8key = KEY12_PRESS;	break;
				case 0xee:	u8key = KEY16_PRESS;	break;
				default:
					break;
			}
		}
	}
	while(KEY_PORT!=0xFe);		//等待第4列所有按键弹起

	return u8key;
}

//通过翻转实现  初始状态设置地位为1  高位为0 也就是00001111 全不通
u8 Key_ColScan(void)//返回被按下的矩阵按键值
{
	u8 u8key = KEY_UNPRESS;
	u8 row,col;
	//扫描第一列
	KEY_PORT = 0x0F;		//无按键按下矩阵状态
	if (KEY_PORT!=0x0F){    //证明有按键按下
		delay_ms(10);       //有个10ms机械按键的触发时间
		if(KEY_PORT!=0x0F){
		   switch(KEY_PORT)
		   {
		   		case 0x0E:
					col=4;
					break;
				case 0x0d:
					col=3;
					break;
				case 0x0b:
					col=2;
					break;
				case 0x07:
					col=1;
					break;
				default:break;
		   }
		   //翻转,将矩阵按键所有的行引脚拉高,所有的列引脚拉低
		   KEY_PORT=0xF0;
		    switch(KEY_PORT)
		   {
		   		case 0xE0:
					row=4;
					break;
				case 0xd0:
					row=3;
					break;
				case 0xb0:
					row=2;
					break;
				case 0x70:
					row=1;
					break;
				default:break;
		   }
			 while(KEY_PORT!=0xF0);//等待按键弹起
		}
		 
	}
	
	 u8key=(row-1)*4+col;
	return u8key;
}

LED点阵

LED点阵

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2250065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++语法·叭

阁下何不乘风起&#xff0c;扶摇直上九万里。 qi fei 目录 内存管理 分区介绍 1.栈区&#xff1a; 2.内存映射段&#xff1a; 3.堆&#xff1a; 4.数据段&#xff1a; 5.代码段&#xff1a; 补充&#xff1a; C内存管理&#xff08;简略回忆&#xff09; C内存…

数据库期末复习题库

1. Mysql日志功能有哪些? 记录日常操作和错误信息&#xff0c;以便了解Mysql数据库的运行情况&#xff0c;日常操作&#xff0c;错误信息和进行相关的优化。 2. 数据库有哪些备份方法 完全备份&#xff1a;全部都备份一遍表备份&#xff1a;只提取数据库中的数据&#xff0…

矩阵重新排列——rot90函数

通过 r o t 90 rot90 rot90函数可以将矩阵进行旋转 用法&#xff1a; r o t 90 ( a , k ) rot90(a,k) rot90(a,k)将矩阵 a a a按逆时针方向旋转 k 9 0 ∘ k\times90^\circ k90∘

挑战用React封装100个组件【001】

项目地址 https://github.com/hismeyy/react-component-100 组件描述 组件适用于需要展示图文信息的场景&#xff0c;比如产品介绍、用户卡片或任何带有标题、描述和可选图片的内容展示 样式展示 代码展示 InfoCard.tsx import ./InfoCard.cssinterface InfoCardProps {ti…

联通云服务器部署老项目tomcat记录

1.先在服务器上安装mysql和tomcat 2.tomcat修改端口 3.在联通云运控平台配置tomcat访问端口&#xff08;相当于向外部提供可访问端口&#xff09; 4.将tomcat项目放在服务器tomcat的webapps里面 5.在mysql里创建项目数据库&#xff0c;运行sql创建表和导入数据 6.在配置文…

Python 删除Word中的表格

在处理Word文档时&#xff0c;我们经常会遇到需要删除表格的情况。无论是为了简化文档结构&#xff0c;还是为了更新内容&#xff0c;删除表格都是一个常见的操作。但是通过手动删除不仅耗时&#xff0c;而且容易出错&#xff0c;本文将介绍如何使用Python通过编程删除Word中的…

讯飞语音转写WebApi 【JS语言】

讯飞语音转写 API 文档 文档地址&#xff1a;https://www.xfyun.cn/doc/asr/ifasr_new/API.html 看到没有 js 版本的 demo&#xff08;音频流模式&#xff09;&#xff0c;所以就搞了一个分享出来 在 React Native 运行环境下测试有效。 1、生成 signa import axios from a…

c++基础开发环境vscode+mingw-w64

c开发需要的基础有两个&#xff1a;编译环境&#xff0c;开发环境。 最简单的编译环境可以用gcc&#xff0c;cl&#xff0c;clongllvm; 开发环境最简单直接用文本编辑器就可以。 但是实际开发都会用ide来做&#xff0c;现代的ide即有开发环境可以写代码&#xff0c;自动补全&am…

DBA面试题-1

面临失业&#xff0c;整理一下面试题&#xff0c;找下家继续搬砖 主要参考&#xff1a;https://www.csdn.net/?spm1001.2101.3001.4476 略有修改 一、mysql有哪些数据类型 1&#xff0c; 整形 tinyint,smallint,medumint,int,bigint&#xff1b;分别占用1字节、2字节、3字节…

LSTM卫星轨道预测(一)

一.多文件预测 代码详细解析 1. 文件读取与数据处理 功能 从 .sp3 文件中读取卫星轨迹数据。提取包括 Satellite_ID, X, Y, Z 等字段的信息。计算派生特征&#xff08;如速度和加速度&#xff09;&#xff0c;便于后续建模使用。 主要函数&#xff1a;extract_sp3_data(fil…

如何通过智能生成PPT,让演示文稿更高效、更精彩?

在快节奏的工作和生活中&#xff0c;我们总是追求更高效、更精准的解决方案。而在准备演示文稿时&#xff0c;PPT的制作往往成为许多人头疼的问题。如何让这项工作变得轻松且富有创意&#xff1f;答案或许就在于“AI生成PPT”这一智能工具的广泛应用。我们就来聊聊如何通过这些…

格网法计算平面点云面积(matlab版本)

1、原理介绍 格网法计算平面点云面积&#xff0c;其思想类似高中油膜法计算面积。其将点云投影到水平面&#xff0c;再将点云划分成尺寸相同的格网。最后&#xff0c;统计格网内包含点的数量number&#xff0c;那么可利用如下公式计算得到点云的面积&#xff1a; Aeranumber*L…

无代码实现可视化GIS+模型+三维

现在的工具是越来越方便了&#xff0c;本来不是做前端的。可以节省很多的人力和时间&#xff0c;更快的搭建自己想要的可视化大屏&#xff0c;看例子 主要由三维的gis地图和模型加上二维的数据表格分析来实现这个可视化界面。 gis地图的设置 每一个gis都要设置世界远点&#x…

Jmeter中的监听器

3&#xff09;监听器 1--查看结果树 用途 调试测试计划&#xff1a;查看每个请求的详细信息&#xff0c;帮助调试和修正测试计划。分析响应数据&#xff1a;查看服务器返回的响应数据&#xff0c;验证请求是否成功。检查错误&#xff1a;识别和分析请求失败的原因。 配置步骤…

kafka进阶_3.消费消息

文章目录 一、消费消息概览1.1、消费示例代码1.2、消费过程 二、消费者组2.1、push & pull2.2、消费者组 三、调度器Coordinator四、消费者分配策略4.1、引言4.2、分配基本流程4.3、分配策略4.3.1、轮询分配策略4.3.2、轮询分配策略 五、消费偏移量5.1、起始偏移量5.2、指定…

用VC2019+MFC 创建一个DLL封装MD工业相机库然后用EXE调用这个相机库采图并且显示

主要描述&#xff1a; 用VC2019MFC 创建一个DLL封装MD工业相机库&#xff0c;再建一个EXE调用这个相机库采图并且显示。 先创建库工程&#xff1a; 新建一个库工程&#xff0c; 创建完成&#xff0c;添加一个DllFunction.h头文件&#xff0c;一个DllFunction.cpp 源文件 拷贝…

ODB 框架

目录 概述 基本工作原理 映射C对象到数据库表 从数据库中加载对象 持久化C对象到数据库 ODB常用接口 表创建预处理 #pragma db Object table 数据表属性 id auto column&#xff08;“xxx”&#xff09; type("xxx") unique index null default&…

ModuleNotFoundError: No module named ‘_ssl‘ centos中的Python报错

1、检查系统有没有openssl&#xff0c;有的话&#xff0c;就是python安装时没有指定openssl openssl version&#xff0c;有输出版本号就有&#xff0c;没有的话&#xff0c;需要手动安装 下载地址 参见https://www.openssl.org/&#xff0c;包括以下版本&#xff1a; https:/…

小程序-基于java+SpringBoot+Vue的微信小程序养老院系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

linux高级系统编程之进程

进程 一个正在进行的程序 并行与并发 并行:执行的程序在不同CPU上同时执行 并发:一个CPU,多个进程交替执行,因为交替速度很快,所以从宏观上来看是同时执行的,但是从围观的角度是交替执行的 单道与多道 单道程序设计:所有进程一个一个排队执行,若A阻塞,B只能等待,,即使CPU处于空…