学会阅读硬件的原理图、数据手册大全

参考: 郭天祥:https://www.bilibili.com/video/BV1DW411a7mz?p=8
韦东山:https://www.bilibili.com/video/BV1ga4y1Y7PL?p=4
洋桃电子:https://www.bilibili.com/video/BV1eW411J7cf?p=2&spm_id_from=pageDriver

目录

  • 硬件接口的四大类
      • 1. GPIO和门电路
      • 2. 协议类
      • 3. 类似内存的接口(ram-like)
      • 4. 模拟电路
  • GPIO与门电路
      • 1. GPIO的应用
      • 2. GPIO引脚操作
        • 2.1 设置引脚为GPIO功能
        • 2.2 设置引脚方向
        • 2.3 设置/读取引脚数值
      • 3. 二极管
      • 4. 三极管
        • 4.1 NPN三极管
        • 4.2 PNP三极管
  • LED电路与操作
      • 1. LED实物
      • 2. LED电路
  • 同步与异步
      • 1. 概念
        • 1.1 同步信号示例
        • 1.2 异步信号示例
      • 2. 差别
  • 使用一线传输双向数据
      • 1. 面临的问题
      • 2. 解决方法
      • 3. 双向传输示例
  • 1602液晶驱动
    • 阅读手册
    • LCD1602.h
    • LCD1602.c

硬件接口的四大类

参考书籍:

  • 《微机原理》:侧重于计算机结构
  • 《数字电子技术基础 》:侧重于门电路

1. GPIO和门电路

GPIO:general peripheral input/ouput,通用的外设输入、输出接口。

这类电路通常只使用一个引脚

  • 可以设置为输出
    • 可以输出高、低电平
    • 比如用来控制LED
  • 也可以设置为输入
    • 可以读取引脚电平,判断当前是高电平还是低电平
    • 比如用来判断按键是否被按下
  • 可以接上各类晶体管(二极管、三极管等)实现逻辑运算

2. 协议类

比如:UART、I2C、SPI、Nand、TFT LCD。

如果两个设备之间要传输的数据比较复杂,可以约定一些规则。这类接口被称为"协议类"接口。

当然可以只使用一条GPIO引脚来传输复杂的数据,比如红外遥控器、温度传感器等。也可使用多条线路来传输数据,比如UART、I2C、SPI等。比如TFT LCD的接口线将近30条。

例子:

  • I2C接口

    • 硬件连接

学会阅读硬件的原理图、数据手册大全_第1张图片

  • I2C协议
    学会阅读硬件的原理图、数据手册大全_第2张图片

3. 类似内存的接口(ram-like)

比如:Nor Flash、SDRAM、DDR、网卡DM9000等。

  • 内存:可以读写某个地址上的数据,所以必定有这些信号
    • 地址总线
    • 数据总线
    • 读/写信号
    • 片选(cs):ram-like接口上可以接多个设备,互相之间不能干扰,选中哪个设备哪个设备才能响应
  • 很多设备也采用类似内存的接口,比如Nor Flash、8080接口的LCD
  • 例子
    学会阅读硬件的原理图、数据手册大全_第3张图片

4. 模拟电路

数字电路上传输的电压值只有2类取值,比如

  • 2.xV到3.3V,抽象为逻辑值1
  • 0V到1.xV,抽象为逻辑值0

模拟电路上传输的电压可以是各种各样的,比如以下两个电路:

  • ADC电路中:可以读取滑动电阻器上的触点电压值
  • DAC电路中:可以输出不同的电压值,用来控制LED的亮度(数字电路里LED只有亮、灭两个状态)

读取滑动电阻器上的触点电压值

  • DAC电路中:可以输出不同的电压值,用来控制LED的亮度(数字电路里LED只有亮、灭两个状态)

学会阅读硬件的原理图、数据手册大全_第4张图片

GPIO与门电路

1. GPIO的应用

GPIO可以设置为输出、输入:

  • 输出功能

    • LED

    • 发射红外信号

    • 控制电机

    • 蜂鸣器

    • 数码管

  • 输入功能

    • 按键
    • 接收红外信号
    • 人体感应
  • 实现各类协议

    • 读取温湿度传感器数据
    • 其实UART等也是使用GPIO来实现的

2. GPIO引脚操作

怎么用一个GPIO来控制LED?换句话说,怎么让一个GPIO输出高、低电平?

2.1 设置引脚为GPIO功能

学会阅读硬件的原理图、数据手册大全_第5张图片

芯片内部有很多模块,比如GPIO、UART(串口)。
一个引脚,可以接到模块A,也可以接到模块B,比如上图中的引脚gpio0_0,可以接到GPIO group 0,也可以接到UART。
可以设置某些寄存器(比如io_mux),选择引脚的功能。

2.2 设置引脚方向

假设一个引脚被设置成了GPIO功能,那么它是用作输出,还是输入?
在GPIO模块内部,一般都有一个方向选择寄存器,里面每一位用来控制一个引脚的方向。
比如GPIO group 0中有一个gpio0_dir_reg寄存器,

  • 它的bit 0写入1,表示gpio0_0被设置为输出
  • 它的bit 0写入0,表示gpio0_0被设置为输入

学会阅读硬件的原理图、数据手册大全_第6张图片

2.3 设置/读取引脚数值

一个GPIO引脚被设置成输出,那么怎样设置它的输出电平?
一个GPIO引脚被设置成输入,那么怎样读取它的输入电平?
在GPIO模块内部,一般都有一个数据寄存器,里面每一位用来控制一个引脚的输出电平。
比如GPIO group 0中有一个gpio0_data_reg寄存器,

  • 写数据
    • 它的bit 0写入1,表示gpio0_0输出高电平
    • 它的bit 0写入0,表示gpio0_0输出低电平
  • 读数据
    • 如果bit 0等于1,表示gpio0_0为高电平
    • 如果bit 0等于0,表示gpio0_0为低 电平

学会阅读硬件的原理图、数据手册大全_第7张图片

3. 二极管

参考资料:图文详解二极管原理

学会阅读硬件的原理图、数据手册大全_第8张图片

  • 二极管的箭头表示正向电流的方向

  • 二极管的电流具有单向性

  • 假设正极、负极之间的电压为V

    • 当V大于某个阈值(比如0.7V),二极管就导通,导通时电阻约等于0
    • 当V<0,二极管不会导通,电阻无穷大
  • 内部结构:由PN节组成,P代表正极(positive),N代表负极(negative)

  • 二极管中流动的是电子,电流方向是从正极到负极,电子流动的方向是从负极到正极

  • 使用二极管

    • 比如:使用二极管防止电源接反是烧坏电路

    学会阅读硬件的原理图、数据手册大全_第9张图片

4. 三极管

参考资料:三极管工作原理分析精辟透彻看后你就懂

可以使用二极管的特性制作成三极管,组成开关电路。

三极管实物图:

学会阅读硬件的原理图、数据手册大全_第10张图片

三极管可以分为:NPN三极管、PNP三极管。

4.1 NPN三极管

学会阅读硬件的原理图、数据手册大全_第11张图片

  • 扩散
    • 物质会从浓度大的地方扩散到浓度低的地方
    • 比如墨水滴入水中,墨水会四处散开
    • 比如臭味会四处散开
    • 电子也会有扩散作用
  • 三极管原理
    • 当be之间的PN节加上正向电压,电子从e极的’N’大量往‘P’移动(所以e被称为发射极)
    • 电子在’P’大量聚集,一部分通过b极流走,另一部分通过c极扩散出去(c起收集作用,所以被称为集电极)
      • 电子流动方向如图中红色箭头所示
      • 电流方向与电子流动方向相反:be之间电流从b到e,ce之间电流从c到e
  • 三极管的使用
    • 当Vcon等于0.7V左右,be之间的PN节打通,c极相当于直接连接e,V2=0
    • 当Vcon等于0V,be之间的PN节没打通,c极相当于断开,V2=V
    • 所以,可以用Vcon来控制V2

4.2 PNP三极管

学会阅读硬件的原理图、数据手册大全_第12张图片

  • 扩散
    • 物质会从浓度大的地方扩散到浓度低的地方
    • 比如墨水滴入水中,墨水会四处散开
    • 比如臭味会四处散开
    • 电子也会有扩散作用
  • 三极管原理
    • 当eb之间的PN节加上正向电压,空穴从e极的’N’大量往‘P’移动(所以e被称为发射极)
    • 空穴在’P’大量聚集,一部分通过b极流走,另一部分通过c极扩散出去(c起收集作用,所以被称为集电极)
      • 空穴流动方向如图中红色箭头所示
      • 电流方向与空穴流动方向相同:eb之间电流从e到b,ec之间电流从e到c
  • 三极管的使用
    • 当Vcon为高电压(比如3.3V),eb之间的PN节打通,c极相当于直接连接e,V2=Vcon
    • 当Vcon等于0V,eb之间的PN节没打通,c极相当于断开,V2=0
    • 所以,可以用Vcon来控制V2

流从e到b,ec之间电流从e到c

  • 三极管的使用
    • 当Vcon为高电压(比如3.3V),eb之间的PN节打通,c极相当于直接连接e,V2=Vcon
    • 当Vcon等于0V,eb之间的PN节没打通,c极相当于断开,V2=0
    • 所以,可以用Vcon来控制V2

LED电路与操作

1. LED实物

学会阅读硬件的原理图、数据手册大全_第13张图片

2. LED电路

学会阅读硬件的原理图、数据手册大全_第14张图片

  • 方式1
    • 芯片引脚输出高电平,LED被点亮
    • 芯片引脚输出低电平,LED被熄灭
    • 缺点:芯片引脚的驱动能力可能不够,LED亮度低
  • 方式2
    • 芯片引脚输出低电平,LED被点亮
    • 芯片引脚输出高电平,LED被熄灭
    • 缺点:电流进入芯片过大时,可能烧毁芯片
  • 方式3
    • 芯片引脚输出高电平,三极管导通,LED被点亮
    • 芯片引脚输出低电平,三极管不导通,LED被熄灭
  • 方式4
    • 芯片引脚输出低电平,第一个三极管不导通,第二个三极管导通,LED被点亮
    • 芯片引脚输出高电平,第一个三极管导通,第二个三极管不导通,LED被熄灭

三极管导通,第二个三极管不导通,LED被熄灭

同步与异步

1. 概念

同步(synchronous)、异步(asynchronous),使用生活例子来说就是:

  • 同步:朋友打电话说到我家吃饭,我在家里等他们
  • 异步:朋友没有提前打招呼,突然就到我家来了

1.1 同步信号示例

在电子产品中,使用同步信号进行传输时,一般涉及两个信号:

  • 时钟信号:用来通知对方要读取数据了
  • 数据信号:用来传输数据

比如:

  • 时钟信号:打电话,起约定作用
  • 数据信号:传输数据

学会阅读硬件的原理图、数据手册大全_第15张图片

1.2 异步信号示例

学会阅读硬件的原理图、数据手册大全_第16张图片

使用异步信号传输数据时,双方遵守相同的约定:

  • 起始信号:发送方可以通知接收方"注意了,我要开始传输数据了"

  • 数据的表示

    • 怎么表示逻辑1
    • 怎么表示逻辑0

以红外遥控器解码器为例,它向单片机发出的数据格式如下:

  • 起始信号:解码器发出一个9ms的低电平、4.5ms的高电平,用来同时对方说"开始了"
    学会阅读硬件的原理图、数据手册大全_第17张图片

  • 表示一位数据

    • 逻辑1:0.56ms的低电平+1.69ms的高电平
    • 逻辑0:0.56ms的低电平+0.56ms的高电平

    学会阅读硬件的原理图、数据手册大全_第18张图片

  • 接收方、发送方都遵守这样的约定,就可以使用一条线传输数据

2. 差别

同步传输 异步传输
信号线 多:时钟信号、数据信号 少:只需要数据信号
速率 可变,提高时钟信号频率即可 双方提前约定
抗干扰能力

使用一线传输双向数据

1. 面临的问题

学会阅读硬件的原理图、数据手册大全_第19张图片

两个设备之间,只使用一条数据线,能否传输双向的数据?

  • A发出高电平,B发出低电平
    • 电路可能被损坏
    • 电路上到底是高电平还是低电平?不能确定
  • 问题在于:有两个设备试图同时驱动电路

2. 解决方法

不让双方同时驱动电路,或者即使同时驱动也没关系:

  • 不让双方同时驱动电路:双方无法约定时间,此方法不可行
  • 即使同时驱动也没关系:可行,电路如下:

学会阅读硬件的原理图、数据手册大全_第20张图片

真值表如下:

A B DATA
0 0 1(由上拉电阻决定)
0 1 0
1 0 0
1 1 0

从真值表和电路图我们可以知道:

  • 当某一个芯片不想影响SDA线时,那就不驱动这个三极管
  • 想让DATA输出高电平,双方都不驱动三极管(SDA通过上拉电阻变为高电平)
  • 想让DATA输出低电平,就驱动三极管

芯片内部的三极管,被称为open collector,开集,也就是在芯片内部三极管的集电极是开放的。
芯片内部不驱动三极管是,集电极的电平由外面的上拉电阻决定。

这种电路实现了:

  • 双方设备即使同时想输出不同的电平:
    • 电路也不会被损坏
    • 电平也是确定的

3. 双向传输示例

  • 初始状态:一开始,双方都不驱动三极管,DATA为高

  • 起始信号和回应:A想传输数据给B,发出开始信号、得到回应信号

    • A检测DATA线,高表示对方没有占用数据线
    • A驱动三极管,使得DATA为低,用来通知B:我就要传输数据了
    • A释放三极管,DATA变为高
    • B驱动三极管,使得DATA为低,用来通知A:好的,我准备好了(这是一个回应信号)
    • B释放三极管,DATA变为高
  • 传输:A发送数据给B,比如传输2位数据0、1

    • 双方都使用同一套数据表示方法,比如使用60US来传输一位数据,数值由DATA电平决定
    • 在第1个60us,A设置DATA为低;在同一时间,B读取DATA电平得到数据0
    • 在第2个60us,A设置DATA为高;在同一时间,B读取DATA电平得到数据1
  • 结束:A释放三极管,DATA变为高电平

    • 在第2个60us,A设置DATA为高;在同一时间,B读取DATA电平得到数据1
  • 结束:A释放三极管,DATA变为高电平

  • 这时候,B也可以使用一样的方法给A传输数据

1602液晶驱动

阅读手册

1602代表:显示16个字符,可以显示两行。如下图所示:
学会阅读硬件的原理图、数据手册大全_第21张图片
学会阅读硬件的原理图、数据手册大全_第22张图片
学会阅读硬件的原理图、数据手册大全_第23张图片

学会阅读硬件的原理图、数据手册大全_第24张图片

学会阅读硬件的原理图、数据手册大全_第25张图片
发现使用上表中的数值芯片不能正常驱动,查看原厂家芯片英文资料,实践可以正常使用,具体数值如下图所示:
学会阅读硬件的原理图、数据手册大全_第26张图片

学会阅读硬件的原理图、数据手册大全_第27张图片
学会阅读硬件的原理图、数据手册大全_第28张图片
学会阅读硬件的原理图、数据手册大全_第29张图片
学会阅读硬件的原理图、数据手册大全_第30张图片
学会阅读硬件的原理图、数据手册大全_第31张图片

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

LCD1602.c

#include 

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//main函数入口
void main()
{
     
	LCD_Init();
	while(1);

}



//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
     
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
     
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
     
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
     
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
     
	if(Line==1)
	{
     
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
     
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
     
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
     
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
     
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
     
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
     
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
     
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
     
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
     
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
     
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
     
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
     
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
     
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
     
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
     
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
     
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
     
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
     
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
     
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

你可能感兴趣的:(单片机,1024程序员节)