单片机复习 实验一 IO口驱动

本节主要内容为基础IO口驱动跑马灯及按键控制LED与蜂鸣器实验,对应课本第5章第1、2小结,另课本例5-2代码也非常经典,运用了与运算、switch-case、do-while语句

基础实验

1、利用单片机及8个发光二极管等器件,构成一个单片机控制的流水灯系统 

基础代码 实现由上至下循环点亮

#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
   
void delay(uint i){
    uchar j;
    while(i--){
        for(j=0;j<255;j++)
    }
}

void main(){
    P1 = 0xfe;   //向P1.0送点亮数据
    while(1){
        delay(500);
        P1 = _crol_(P1,1);  //向左循环移1位
    }
}

知识点1

_crol_:循环左移(left)

_cror_:循环右移(right)

使用循环移位符时需要 #include <intrins.h>

拓展代码 实现由上至下,再由下至上反复循环点亮显示的流水灯

(1)数组的字节操作实现 用tab[ ]实现

uchar tab[] = {0xfe~0xfe};  //前8个数据为由上至下点亮数据,后8个为由下至上点亮数据
                            //内容需自己补充完整

void delay(){
    uchar i,j;
    for(i=0;i<255;i++);
    for(j=0;j<255;j++);
}

void main(){
    while(1){
        for(i=0;i<16;i++){
            P1 = tab[i];
            delay();
        }
    }
}

 (2)字节运算符实现  用>>和<<符号实现

void main(){
    uchar temp,i;
    while(1){
        temp = 0x01;
        for(i=0;i<8;i++){
            P1 = ~temp;
            delay();
            temp<<1;
        }
        temp = 0x80;
        for(i=0;i<8;i++){
            P1 = ~temp;
            delay();
            temp>>1;
        }
    }
}   

Q:为什么在这段代码中要先赋给变量temp=0x01后再取反?

因为>>和<<运算符与循环移位函数不同,<<会在移位时将高位丢弃,低位置0,而P1口送0时LED灯才会亮

(3)通过循环移位符实现

void main(){
    while(1){
        temp = 0xfe;
        for(i=0;i<7;i++){
            P1 = temp;
            delay();
            temp = _crol_(temp,1);
        }
        for(i=0;i<7;i++){
            P1 = temp;
            delay();
            temp = _cror_(temp,1);
        }
    }
}    

注意:这里的循环中i<7,因为一开始就已经置temp为第一个灯亮了

拓展实验一

按键控制LED灯

#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define in  P3
#define out P1

// 延时函数,延时大约 10 毫秒
void Delay10ms()  
{
    uint i, j;
    for (i = 100; i > 0; i--)
        for (j = 120; j > 0; j--);
}

void main(void)
{
    uchar i;
    bit m;
    while (1)
    {
        for (i = 0; i < 8; i++) // 扫描 P3 口的按键
        {
            m = (in >> i) & 0x01; // 获取 P3 的第 i 位输入状态
            if (m == 0) // 检测按键是否按下
            {
                Delay10ms(); // 延时 10 毫秒消抖
                if (m == 0) // 再次确认按键状态
                {
                    out = _crol_(0xFE, i); // P1 口输出点亮对应位置 LED 灯
                }
            }
        }
    }
}

拓展实验二

按键控制蜂鸣器

12dd3e9126fd46c8b91eba27439172f9.png

工作原理:
当单片机P2口输出高电平时,基极电流流入三极管,使其进入饱和导通状态。
三极管导通后,蜂鸣器负极接地,电流通过蜂鸣器形成回路,蜂鸣器因此发声。
当P2口输出低电平时,三极管截止,蜂鸣器无电流流过,因而不发声

#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
	
sbit key=P3^2  ;  
sbit BUZZER=P2^3;

void delayms(uchar ms)
{
	uchar i;
	while(ms--)
	{
		for(i=0;i<120;i++);
	}
}

void beep()
{
	BUZZER=1;
	delayms(2000);
	BUZZER=0;
	delayms(2000);	
}

void check_key()
{
	if (key==0){
		beep();
		beep();
		beep();
		while(key==0);
	}
}

void main()
{
	BUZZER=0;
	while(1)
	{
			check_key();
	}
}

 延时消抖优化

void check_key()
{
    if (key == 0) {
        delayms(20);  // 延时去抖
        if (key == 0) {
            beep();
            beep();
            beep();
            while (key == 0);  // 等待按键松开
        }
    }
}

Q:如果不加while (key == 0);  // 等待按键松开 会发生什么?

  • 蜂鸣器会因按键持续按下而重复鸣叫,功能表现不符合设计预期。
  • 主程序循环的效率会降低,逻辑可能陷入重复执行。

拓展实验三 

按键控制流水灯

4个按键

#include <reg51.h>
#define uchar unsigned char

#define LED P2
sbit key1 = P1^4;
sbit key2 = P1^5;
sbit key3 = P1^6;
sbit key4 = P1^7;

uchar mode = 0;

void delayms(uchar ms) {
    uchar i;
    while(ms--) {
        for(i = 0; i < 120; i++);
    }
}

void check_button() {
    if(key1 == 0) {
        delayms(10); // 按键消抖
        if(key1 == 0) {
            mode = 1;
            while(key1 == 0);
        }
    }
    if(key2 == 0) {
        delayms(10); // 按键消抖
        if(key2 == 0) {
            mode = 2;
            while(key2 == 0);
        }
    }
    if(key3 == 0) {
        delayms(10); // 按键消抖
        if(key3 == 0) {
            mode = 3;
            while(key3 == 0);
        }
    }
    if(key4 == 0) {
        delayms(10); // 按键消抖
        if(key4 == 0) {
            mode = 4;
            while(key4 == 0);
        }
    }
}

void led_mode()
{
	switch(mode)
	{
		case 1:
			LED=0x00;
			break;
		case 2:
			LED=0x55;
			delayms(2000);
			LED=0xAA;
			delayms(2000);
			break;
		case 3:
			LED=0xF0;
			break;
		case 4:
			LED=0x0F;
			break;
		}
}


void main() {
    LED = 0xFF; // 初始化LED状态
    while(1) {
        check_button();
        led_mode();
    }
}

1个按键

#include <reg51.h>
#define uchar unsigned char

sbit S = P1^4;
#define LED P2

uchar mode = 0;

void delayms(uchar ms)
{
    uchar i;
    while(ms--)
    {
        for(i = 0; i < 120; i++);
    }
}

void check_button()
{
    if(S == 0) {
        delayms(10);  // 按键消抖
        if(S == 0) {  // 确认按键状态
            mode++;
            if(mode > 4) {
                mode = 0;
            }
            while(S == 0);  // 等待按键释放
        }
    }
}

void led_mode()
{
    switch(mode)
    {
        case 0:
            LED = 0xFF;  // 所有灯灭
            break;
        case 1:
            LED = 0x00;  // 所有灯亮
            break;
        case 2:
            LED = 0x55;  // LED 闪烁
            delayms(2000);
            LED = 0xAA;
            delayms(2000);
            break;
        case 3:
            LED = 0xF0;  // 前四灭,后四亮
            break;
        case 4:
            LED = 0x0F;  // 前四亮,后四灭
            break;
    }
}

void main()
{
    LED = 0xFF;  // 初始化为所有灯灭
    while(1) {
        check_button();
        led_mode();
    }

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值