嵌入式硬件-51单片机

本系列博客以STC98552RC芯片为示例学习。

一.基本概念

1.单片机基础

2.CPU与内存交互

3.位运算

示例(操作 P2.1)
把某位置 1P2 |= (1 << 1);
把某位清 0P2 &= ~(1 << 1);
翻转某位P2 ^= (1 << 1);
判断某位是否为1if (P2 & (1 << 1))
判断某位是否为0if (!(P2 & (1 << 1)))
同时操作多位

同时置位 P2.0 和 P2.1:

P2 |= (1 << 0) | (1 << 1)

同时清零 P2.0 和 P2.1:

P2 &= ~((1 << 0) | (1 << 1))

定时器高低位赋值    TL0 = num;
    TH0 = num >> 8;

4.逻辑分析仪

  1. 共地(最重要)
    逻辑分析仪的 GND 必须和单片机的 GND 连在一起,否则电平没有参考点,抓出来的波形全是乱码或噪声。

  2. 电压匹配
    51 单片机一般是 5V 电平,大多数廉价逻辑分析仪支持 5V 输入(但有些只支持 3.3V)。接之前最好确认一下你的逻辑分析仪输入电压范围,避免烧坏。

  3. 不要接错电源
    逻辑分析仪的通道输入是高阻抗的,只测信号,不会给单片机供电。千万别把 VCC 接到逻辑分析仪的通道上,只接信号线和 GND。

二.硬件详解

1.led

共阳极二极管,低电平导通

void led_init(void)
{
	P2 = 0xFF;
}

void led_all_on(void)
{
	P2 = 0;
}

void led_all_off(void)
{
	P2 = 0xFF;
}

void led_nor(void)
{
	P2 ^= 0xFF;    
}

void led_on(unsigned int n)   
{
	P2 = ~n;	  
}

2.数码管,三极管

四个NPN共阴极三极管控制位选,P0寄存器引脚控制段选

// 共阴极段码表
unsigned char seg_table[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
//0-9
// 位选
void Select_Bit(unsigned int n)
{
	// P1寄存器低四位清零
	P1 &= ~(0x0F << 0);
	// 选中第n位数码管
	P1 |= (1 << n);
}

// 段选
void Select_Seg(unsigned int n)
{
	 P0 = seg_table[n];
}

// 数码管动态显示
void Digiter_show(unsigned int n)  // 1234  
{
	  int m = 0;
	  int t = 0; 

	  while (n != 0)
	  {
	  	 m = n % 10;
		 P0 = 0;
		 Select_Bit(t++);
		 Select_Seg(m);
		 delay(100);
		 n /= 10;
	  }	
}

3.按键

初始化:

P1 |= (0x0F << 4);   // 把 P1.4、P1.5、P1.6、P1.7 置 1
P3 |= (1 << 5);      // 把 P3.5 置 1

//硬件本应实现下拉电阻,将按键初始为高电平状态,但本芯片硬件无实现,故通过软件置1.

按键的“初始化”只是把引脚设为输入状态,之后引脚电平变化是硬件自动完成的,不需要再调用初始化函数。

状态引脚电平原因
按键松开高电平(1)引脚内部有弱上拉(或外接上拉电阻),把电平拉到 VCC
按键按下低电平(0)按键把引脚直接短接到 GND,强行拉低

检测按键:

	if ((P1 & (1 << 4)) == 0)  // 检测到第一个按键被按下
	{
	   ret = 1;
	}
	else if ((P1 & (1 <<5)) == 0)
	{
	   ret = 2;
	}
	else if ((P1 & (1 << 6)) == 0)
	{
		ret = 3;
	}
	else if ((P1 & (1 << 7)) == 0)
	{
		ret = 4;
	}
	else if ((P3 & (1 << 5)) == 0)
	{
		ret = 5;
	}

4.中断

以外部中断0为例:

// 外部中断0 中断服务函数
void int0_handler(void)		interrupt 0
{
   	g_i++;				  //由于硬件存在一定误差,会出现中断触发不稳定,不会按照理想情况一次次触发
}
// 外部中断0初始化
void int0_init(void)
{
	// 1. int0:P3_2引脚拉高
	P3 |= (1 << 2);

	// 2. 外部中断0子开关 + CPU中断开关
	IE |= (1 << 0) | (1 << 7);

	// 3. 外部中断0引脚中断触发方式:下降沿触发
	TCON |= (1 << 0);
}

5.定时器

// 定时器0中断服务函数
void timer0_handle(void) 	interrupt 1
{
	TL0 = g_x;
	TH0 = g_x >> 8;

	P2 ^= (1 << 1);	   
}

// 定时器0初始化
void timer0_init(void)
{
	// 1. 配置定时器0模式:16位定时器
	TMOD &= ~(0x0F << 0);  
	TMOD |= (1 << 0);

	// 2. 设置定时器初值	 11.0592MHZ:64626  12MHZ:64535
	TL0 = g_x;
	TH0 = g_x >> 8;

	// 3. 开启定时器0,开始计数
	TCON |= (1 << 4);

	// 4. 开启定时器0中断 + CPU总中断
	IE |= (1 << 1) | (1 <<7);
}

6.蜂鸣器

  1. 单片机引脚 P21(P2.1)通过电阻 R22 (1kΩ) 连到了 NPN 三极管 Q5 的基极(B)

  2. 三极管 Q5 的发射极(E)直接接了 GND(地)。

  3. 跳线帽的作用,就是把 P21 和这个三极管基极“连在一起”。

  4.  为什么连在一起,P21 就是低电平了?(核心原理)

    在 NPN 三极管内部,基极(B)和发射极(E)之间,相当于一个二极管(PN结)。

    当单片机程序想把 P21 输出高电平(1),用来关掉 D2 灯时,电流会顺着 P21 → R22 → 三极管基极。
    由于三极管的发射极是接地的,这个电流会直接通过基极-发射极这个“二极管”流向 GND。

    结果:这个 PN结会把 P21 的电压死死“钳位”在约 0.7V,而不是希望的 5V。
    在数字电路里,0.7V 被判定为逻辑低电平(0)。所以,跳线帽插着的时候,P21 永远无法维持高电平,D2 灯(低电平点亮)就永远亮着。

  5. 这个电路设计其实是“高电平驱动”的 NPN 蜂鸣器。也就是给 P21 高电平,蜂鸣器才响。但之前 D2 灯是“低电平亮”。这就导致两个功能完全冲突:灯亮意味着低电平,蜂鸣器不响;蜂鸣器响意味着高电平,灯灭。这就是硬件复用的坑,所以只能用跳线帽物理隔离。

蜂鸣器发声原理:根据发声频率与单片机工作频率计算定时器初值,发声频率越高,单次发声间隔越短,定时器初值越高(越接近溢出值),中断执行越频繁,蜂鸣器发声频率也就变高,实现了不同频率发声。

无源蜂鸣器一个震荡发声一次:

  • 每次定时器中断 → 引脚电平翻转一次

  • 两次中断 → 电平翻转两次 (一个完整周期)。

  • 每秒发生多少个完整周期 → 就是发声频率(Hz)。

#define HZ_200	63035
#define HZ_400	64285
#define HZ_600  64702
#define HZ_800	64910
#define HZ_1000	65035
蜂鸣器类型P2.1 持续高电平的结果原因
有源蜂鸣器一直响内部自带振荡电路,只要通电就发声
无源蜂鸣器不响(或只“嗒”一声)内部没有振荡电路,必须靠外部不断翻转电平(方波)驱动
// 定时器0中断服务函数
void timer0_handle(void) 	interrupt 1
{
	TL0 = g_x;
	TH0 = g_x >> 8;

	P2 ^= (1 << 1);	   
}//P2.1引脚连接蜂鸣器与led的D2灯,通过不断对P2电平翻转实现蜂鸣器工作

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值