嵌入式开发硬件——单片机

发布于:2025-08-08 ⋅ 阅读:(17) ⋅ 点赞:(0)
1、单片机最小系统

单片机外部:

电源

时钟:12M晶振,1/(2*6)分频【决定工作效率】

复位:(强制重启)

单片机内部:

RAM(随机存储器):掉电数据丢失,运行在这里。访问速率快

ROM(只读存储器):掉电数据不丢失,文件保存在这里,访问速率慢

2、51相关知识

有电势差(1v-2v),led灯才能亮

原理图:表示器件的逻辑连接关系;PCB:表示器件的物理连接关系

电容:滤波作用

电阻:负载作用,限制电流,排阻(104表示 10的3次方)

3、流水灯

时钟周期:12M hz

机器周期:

1M hz(主频)

void Delay_ms(unsigned int num)		
{
	unsigned char i, j;
	while(num--)
	{
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}
4、数码管

array[]里面存储的是0123456789abcdef,表示的数码管的abcdefg横线的1和0

digit_select()控制数码管显示的位置:

1、0x7  0000 0111>>2=0001 1100   1110 0011   代表p2.2 p2.3 p2.4端口为0

2、将digit(0-7)左移2位,存入P2.2-P2,4,其他位不变

练习:输入四位数字,显示该四位数字

#include<reg51.h>
void Delay_ms(unsigned int num)		
{
	unsigned char i, j;
	while(num--)
	{
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}
void digit_select(unsigned char digit)
{
	unsigned char num=P2;
	num &= ~(0x7<<2);
	num |=(digit<<2);
	P2=num;
}
unsigned char array[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void digit_show_num(unsigned int num)
{
	 unsigned char digit[4];
	 unsigned  int i;
	 digit[3]=num%10;
	 digit[2]=(num/10)%10;
	 digit[1]=(num/100)%10;
	 digit[0]=num/1000;
	 for(i=0;i<4;i++)
	 {
	 	digit_select(i);
		P0=array[digit[i]];
		Delay_ms(5);
	 }
}
void main(void)
{
	unsigned int dat=1234;
	while(1)
	{
		digit_show_num(dat);
	};
}
5、8*8点阵模块

74HC595(串转并)模块

特点:8位串行输入,8位串行或并行输出,100MHZ的移位频率,输出寄存器可以直接清除

p35控制移位,p36控制输出

行数控制移位,列数控制哪个灯亮

行数高电平,列数低电平,灯亮

消影

SRCLK=0;SRCLK=1;上升沿,把每一位数据数据寄存器的数据移位

RCLK=0;RCLK=1;上升沿,把移位寄存器的数据给数据存储寄存器

SER

练习:滚动显示0-9

#include <reg51.h>
sbit RCLK = P3^5;//表示取P3端口的第5位,不是异或
sbit SRCLK = P3^6;
sbit SER = P3^4;
unsigned char code h_data[10 * 8] = 
{
	0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00,
	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x7E, //数字1
	0x00, 0x3c, 0x08, 0x10, 0x20, 0x3c, 0x00, 0x00,//数字2
	0x00, 0x3c, 0x04, 0x04, 0x3c, 0x04, 0x04, 0x3c, //数字3
	0x00, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x04, 0x04, //数字4
	0x3C, 0x20, 0x20, 0x3C, 0x04, 0x04, 0x3C, 0x00,  // 数字5
	0x00, 0x3c, 0x20, 0x20, 0x3c, 0x24, 0x3c, 0x00,  //数字6
	0x00, 0x3c, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, //数字7
	0x7E, 0xC3, 0xC3, 0x7E, 0xC3, 0xC3, 0xC3, 0x7E,  //数字8
	0x00, 0x18, 0x24, 0x24, 0x1C, 0x04, 0x24, 0x18 //数字9
};
void delayn(unsigned char n)
{
	while(n--);
}
void write_74hc595(unsigned char dat)
{
	unsigned char i = 0;
	for(i = 0; i < 8; i++)
	{
		if(dat & (1 << (7 - i)))// 检查当前位是否为1
		{
			SER = 1;
		}
		else
		{
		   SER = 0;
		}
		SRCLK = 0;   
		delayn(1);
		SRCLK = 1;
		delayn(1);      
	}
	RCLK = 0;
	delayn(1); 
	RCLK = 1;
}
void main(void)
{
	unsigned char i = 0;
	unsigned char j = 0;
	unsigned char k = 0;
	unsigned char num = 0;
	while(1)
	{
//首列(h_data[j])会被显示 80 次,其他列(h_data[j+1]~h_data[j+7])显示 20 次。
		if(j % 8 == 0)
			num = 80;
		else
			num = 20;
		for(k = 0; k < num; k++)//显示很多遍
		{
			for(i = 0; i < 8; i++)
			{
				write_74hc595(1 << (7 - i));	 
				P0 = ~h_data[i + j];//共阳极,低电平有效
				delayn(100);
				P0 = 0xff; // 消除残影
			}
		}
		j++;
		if(j > 72)//上面有i+j
			j = 0;
	}
}
6、独立按键模块

注意点:

LED模块显示的数字是从右往左看,且亮灯代表0,不亮灯代表1

比如:

0x23(0010 0011),led显示应为:

1100 0100

不亮,不亮,亮,亮,亮,不亮,亮,亮

!(P3 & (1<<3))        记住

1<<3 0000 0001   0000 1000

P3=0XB0  1011 0000

1011 0000  &  0000 1000 一假则假

0000 0000

取反 1111 1111

代码:

void main()
{
	while(1)
	{
		if(!(P3 & (1<<3)))//代表得到P33
			P2=0X23;
		else
			P2=0Xff;
		if(!(P3 & (1<<2)))
			P2=0Xbb;
	}
}
7、矩阵按键模块

重点,有些许没搞懂

代码:

unsigned char get_key_value(void) {
    unsigned char col, row_val;

    // 扫描 4 列(P1.0-P1.3)
    for (col = 0; col < 4; col++) {
        P1 = ~(1 << col);  // 当前列置低电平,其他列高电平
        if ((P1 & 0XF0) != 0xF0) {  // 如果有按键按下(行不全为1)
                // 检测具体哪一行被按下,并控制 P2 输出
                if (!(P1 & (1 << 4))) P2 = ~(0x10 >> col);  // 第1行
                if (!(P1 & (1 << 5))) P2 = ~(0x0C >> col);  // 第2行
                if (!(P1 & (1 << 6))) P2 = ~(0x08 >> col);  // 第3行
                if (!(P1 & (1 << 7))) P2 = ~(0x04 >> col);  // 第4行
        }
    }
	return 0;
}
void main()
{
    unsigned char key=0;
    unsigned char dst=0;
	while(1)
	{
	  key=get_key_value();
	  if(key!=0)
	  {
	  	dst=key;
	  }
	}
}
 8、外部中断

程序顺序执行时,产生中断,要去执行中断服务程序,然后再回来执行原程序

51单片机5个中断源的优先级:

详见如图:

代码:实现按k3数字增加,k4数字减小

#include<reg51.h>
sbit SRCLK=P3^6;  //11 SRCLK管脚
sbit RCLK=P3^5; //12 RCLK管脚
sbit SER=P3^4; //14 SER管脚
unsigned char code h_data[10 * 8] = 
{
	0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00,
	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x7E, //数字1
	0x00, 0x3c, 0x08, 0x10, 0x20, 0x3c, 0x00, 0x00,//数字2
	0x00, 0x3c, 0x04, 0x04, 0x3c, 0x04, 0x04, 0x3c, //数字3
	0x00, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x04, 0x04, //数字4
	0x3C, 0x20, 0x20, 0x3C, 0x04, 0x04, 0x3C, 0x00,  // 数字5
	0x00, 0x3c, 0x20, 0x20, 0x3c, 0x24, 0x3c, 0x00,  //数字6
	0x00, 0x3c, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, //数字7
	0x7E, 0xC3, 0xC3, 0x7E, 0xC3, 0xC3, 0xC3, 0x7E,  //数字8
	0x00, 0x18, 0x24, 0x24, 0x1C, 0x04, 0x24, 0x18 //数字9
};
void delay(unsigned char i)//延时函数
{
   while(i--);
}
void Hc595pro(unsigned char dat) //发送段选数据函数
{
  	 unsigned char a=0;
	 for(a=0;a<8;a++)
	 {
		 if(dat&(1<<(7-a)))
		 {
		 	SER=1;
		 }else
		 {
		 	SER=0;
		 }
		 SRCLK=0;
		 delay(1);
		 SRCLK=1;
		 delay(1);
	 }
	 RCLK=0;
	 RCLK=1;
}
void enit0_init(void)
{
	IT0=1;
	EA=1;
	EX0=1;
}
void enit1_init(void)
{
	IT1=1;
	EA=1;
	EX1=1;
}
unsigned char num=0;
void enit0_hanlder(void) interrupt 0
{
    P2=0X0f;
	if(num<9)num++;
	P2=~num;                     
}
void enit1_hanlder(void) interrupt 2
{
    P2=0Xf0;
	if(num>0)num--;
	P2=~num;                     
}
void main()
{
	unsigned char key = 0;
	unsigned char k = 0;
	unsigned char i = 0;
	unsigned char dst = 0;
	unsigned char j = 0;
	unsigned char abs = 0;
	enit0_init();
	enit1_init();
 	while(1)		   // 0   4    8  
	{
		for(j = 0; j <= abs; j++)
		{
			for(k = 0; k < 30; k++)
			{
				for(i = 0; i < 8; i++)
				{
					Hc595pro(1 << (7 - i));
					P0 = ~h_data[i + num * 8];
					delay(100);
					P0 = 0xff;
				}
			}
		}	
	}
}
9、定时器/计数器

计时器/定时器的核心部件是一个加法计数器

1、16位定时器最大计数值65535,所以初值 =65535-50000=15536=0x3caf

2、TMOD &= ~(0x1<<2);清除TMOD的第2位(bit2)

3、TMOD &= ~(0x1<<3);清除TMOD的第3位(bit3)

4、TMOD &= ~(0x3<<0);         TMOD |= (0x01<<0);

这两行代码组合起来实现了:

先清零TMOD的bit0和bit1(M1和M0)

然后设置M0=1,M1=0

代码:实现时间显示

#include <reg51.h>
unsigned char array[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71,0x40};
unsigned char sec = 0;  
void delay_ms(unsigned int num)
{
	unsigned char i, j;
    while(num--)
	{
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}
void timer0_init(void)
{
	TH0=0x4c;  //(65535-50000)/256;0x3c
	TL0=0x00;  //(65535-50000)%256;0caf
	TMOD &=~(0X1<<2);//设置计数器的时钟来源
	TMOD &=~(0X1<<3);//GATE设置为0
    //设置模式为16位定时器
	TMOD &=~(0X3<<0);
	TMOD |=(0X01<<0);
	ET0=1;
	EA=1;
	TR0=1;
}
void timer0_hanlder(void) interrupt 1
{
	static unsigned char timer0_num= 0;
	TH0=0x4c;	//(65535-50000)/256;
	TL0=0x00;	//(65535-50000)%256;	
	TR0=1;
	timer0_num++;
	if(20==timer0_num)//20*50ms=1s
	{	
		sec++; 
		timer0_num=0;
	}	
}
void  digit_select(unsigned char digit,unsigned char seg)  // 0~7
{
    unsigned char num = P2;
	num &= ~(0x7 << 2);	    
	num |= (digit << 2);
	P2 = num;
	P0=seg;	   
}
void main(void)
{
	unsigned char hour = 23;
	unsigned char min = 55; 
	timer0_init();
	while(1)
	{
		if(60==sec)
		{
			min++;
			sec=0;
			if(60==min)
			{
				hour++;
				min=0;
				if(24==hour)
				{
					hour=0;
				}
			}
		}      
		digit_select(0,array[sec%10]);
		delay_ms(2);
		digit_select(1,array[sec/10]);
		delay_ms(2);		
		digit_select(2,array[16]);		
		delay_ms(2);
		digit_select(3,array[min%10]);
		delay_ms(2);
		digit_select(4,array[min/10]);
		delay_ms(2);
		digit_select(5,array[16]);
		delay_ms(2);		
		digit_select(6,array[hour%10]);		
		delay_ms(2);
		digit_select(7,array[hour/10]);
		delay_ms(2);
   	}	
}
10、串口通信

单工,半双工,全双工?

并行:一次性全部传输(两根及以上的数据线)

串行:一个一个传输(一根数据线)

同步:通信双方使用同一个时钟

异步:通信双方使用不同的时钟

波特率:单位时间内传输的码元数(比特率)

小tips:

电压是两点之间的电势差,必须两点都有电压

串行口控制寄存器:PCON和SCON

11、DS18B20

DS18B20 采用单总线通信协议,初始化是主机(MCU)与从机(DS18B20)建立通信的第一步。核心步骤如下:

主机发送复位脉冲:拉低总线至少480µs,然后释放(高电平)。

从机响应存在脉冲:DS18B20 检测到上升沿后,等待15-60µs,拉低总线60-240µs作为应答。

总线恢复空闲:从机释放总线,主机检测到应答后确认设备在线。

写0

  • 主机拉低总线 60µs~120µs,释放总线,进入恢复时间。
  • 从机在主机拉低后的 15µs~30µs 窗口内采样总线

写1:

  • 主机拉低总线 1µs~15µs(短暂脉冲)。
  • 从机快速释放总线,总线被上拉电阻拉高

读0/1:

  • 主机拉低总线 ≥1µs(启动读时间片),在15µs内释放总线并切换为输入模式(高阻态),在拉低后的 15µs~30µs 窗口内读取总线电平(低="0",高="1")
  • 若从机发送"0":主动拉低总线并保持至时间片结束(图中 DS1820 active low,若发送"1":不动作,总线由上拉电阻维持高电平

上课认真听,不要依赖于视频,不懂知识点记下来,自学给它搞懂

看一遍代码,再独立自己写


网站公告

今日签到

点亮在社区的每一天
去签到