IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 51单片机笔记 -> 正文阅读

[嵌入式]51单片机笔记

51单片机笔记

1. 矩阵键盘

H3 H2 H1 H0 L3 L2 L1 L0

1 1 1 1 0 0 0 0 0XF0

1 1 1 0 0 0 0 0 0XE0

0 0 0 0 1 1 1 1 0X0F

0 0 0 0 1 1 1 0 0X0E

temp=0xe0+0x0e=0xee (H0,L0)

2. 定时器/计数器

在这里插入图片描述

2.1 定时器

void inittimer0()
{
    TMOD=0x10;		//0000 0001
    TH0=(65536-50000)/256;	//50000us	256=2^8
    TL0=(65536-50000)%256;	//取低8位
    ET0=1;	//开启定时器0的中断
    EA=1;	//开启总中断
    TR0=1;	//启动定时器0
}
//0:外部中断0	1:定时器中断0	2:外部中断1
//3:定时器中断1	4:串口中断
//interrupt 1	//进入中断(与工作方式无关)
void timer0_isr()	interrupt 1
{
    //进行初值重载
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    //进入中断执行操作
    cnt++;
    if(cnt==20)	//每20*50000us=1s,执行一次num++
    {
        num++;
        cnt=0;
    }
}

2.2 计数器

void initcounter0()
{
    TOMD=0x60;	//0000 0110
    TH0=256-3;
    TL0=256-3;
    ET0=1;
    EA=1;
    TR0=1;
}
void counter0_isr()	interrupt 1
{
    num++;
}

3. 中断

在这里插入图片描述

3.1 外部中断

//初始化外部中断0
void initex()
{
    //(1:下降沿触发;0:低电平触发)
	IT0=1;	//设置外部中断触发方式
	EX0=1;	//开启外部中断0
	EA=1;	//开启总中断
}
//配置外部中断入口
void ex_isr	interrupt 0
{
    /*触发中断后要执行的内容*/
}

4. 串形口通信

在这里插入图片描述
在这里插入图片描述

5. LCD1602

在这里插入图片描述
在这里插入图片描述

6. 点阵

在这里插入图片描述

点阵0-9数字显示(高电平有效)

0x00, 0x7E, 0xFF, 0xC3, 0xC3, 0xFF, 0x7E, 0x00, //0
0x00, 0x00, 0x43, 0xFF, 0xFF, 0x03, 0x00, 0x00, //1
0x00, 0x63, 0xC7, 0xCF, 0xDB, 0xF3, 0x63, 0x00, //2
0x00, 0x42, 0xDB, 0xDB, 0xDB, 0xFF, 0x66, 0x00, //3
0x00, 0x3E, 0x46, 0xFF, 0xFF, 0x06, 0x06, 0x00, //4
0x00, 0xF6, 0xF7, 0xD3, 0xD3, 0xDF, 0xDE, 0x00, //5
0x00, 0x7E, 0xFF, 0xDB, 0xDB, 0xDF, 0x4E, 0x00, //6
0x00, 0xC0, 0xC0, 0xC7, 0xFF, 0xF8, 0xC0, 0x00, //7
0x00, 0xFF, 0xFF, 0xDB, 0xDB, 0xFF, 0xFF, 0x00, //8
0x00, 0x72, 0xFB, 0xDB, 0xDB, 0xFF, 0x7E, 0x00, //9

code:告诉单片机,我定义的数据要放在ROM(程序存储区)里面,写入后就不能再更改

7. A/D和D/A工作原理

7.1 D/A:数字量/模拟量转换器

数字量:一系列的0和1组成的二进制代码表示某个信号大小的量

模拟量:温度、压力、位移、图像等

7.1.1 倒T形电阻解码网络D/A转换器

在这里插入图片描述

7.1.2 DAC0832

电流型 8位 T型电阻解码网络 D/A转换器芯片

在这里插入图片描述

7.2 A/D:模拟量/数字量转换器

7.2.3 ADC0808/0809

8位CMOS逐次逼近型A/D转换器芯片

在这里插入图片描述

在这里插入图片描述

8. 直流电机

输入或输出为直流电能的旋转电机

8.1 L293D

在这里插入图片描述

在这里插入图片描述

停止:电机自然停下

刹停:电机突然停下

9. 步进电机

电脉冲信号转变为角位移或线位移

9.1 L298

9.2 四相步进电机

10. LCD12864

10.1 基本代码

#define LCD_databus P0 //总线接口,注意51的P0口需要外接上拉电阻
sbit DI = P2^2;	//DI为 0:写指令或读状态,1:数据
sbit RW = P2^3;	//1:写 0:读
sbit EN = P2^4;	//使能
sbit CS1 = P2^0;	//片选1.低电平有效,控制左半屏
sbit CS2 = P2^1;  //片选2,低电平有效,控制右半屏
 
void Read_busy()
{
	P0 = 0X00;
	DI = 0;
	RW = 1;
	EN = 1;
	while(P0 & 0x80)
	{;}
	EN = 0;
}

void write_LCD_command(uint8 value)	//写命令函数
{
	Read_busy();
	DI = 0; //0:写指令
	RW = 0;	//0:写操作
	LCD_databus = value;
	EN = 1;	//EN下降沿锁存有效数据
	_nop_();
	_nop_();
	_nop_();//空指令,短暂延时
	EN = 0;
}

void write_LCD_data(uint8 value)	//写数据函数
{
	Read_busy();
	DI = 1; //1:写数据
	RW = 0;	//写操作
	LCD_databus = value;
	EN = 1; //EN下降沿锁存有效数据
	_nop_();
	_nop_();
	_nop_();//空指令,短暂延时
	EN = 0;
}

void Set_page(uint8 page)	//设置显示起始页(一页是8*8的方框)
{
	page = 0xB8 | page;	//页的首地址为0xB8
	write_LCD_command(page);
}

void Set_line(uint8 startline)	//设置显示起始行
{
	startline = 0xC0 | startline;
	write_LCD_command(startline);
}

void Set_column(uint8 column)	//设置显示的列
{
	column = column & 0x3F;	//列的最大值为64
	column = column | 0x40;	//列的首地址为0x40
	write_LCD_command(column);
}	

void SetOnOff(uint8 onoff)	//显示开关函数,0x3E:关 0x3F:开
{
	onoff = 0x3E | onoff;	//onoff为0时关显示,为1时开显示
	write_LCD_command(onoff);
}

void SelectScreen(uint8 screen)	//选择屏幕
{
	switch(screen)
	{
		case 0:CS1 = 0;CS2 = 0;break;//全屏
		case 1:CS1 = 0;CS2 = 1;break;//左半屏
		case 2:CS1 = 1;CS2 = 0;break;//右半屏
		default:break;
	}
}

void ClearScreen(uint8 screen)	//清屏
{
	uint8 i,j;
	SelectScreen(screen);
	for(i=0;i<8;i++)
	{
		Set_page(i);
		Set_column(0);
		for(j=0;j<64;j++)
		{
			write_LCD_data(0x00);	//写入0,地址指针自动加1
		}
	}
}

void InitLCD()
{
	Read_busy();
	SelectScreen(0);
	SetOnOff(0);
	SelectScreen(0);
	SetOnOff(1);
	SelectScreen(0);
	ClearScreen(0);
	Set_line(0);
}

//写16*16的汉字
void show_ch(uint8 screen,uint8 page,uint8 column,uint8 *p)
{
	uint8 i;
	SelectScreen(screen);	//选择屏幕
	Set_page(page);			//选择起始页
	Set_column(column);		//选择起始行
	
	for(i=0;i<16;i++)	//采用16*16的字模
	{
		write_LCD_data(p[i]);
	}
	
	Set_page(page+1);
	Set_column(column);
	for(i=0;i<16;i++)	//采用16*16的字模,"小四号字"
	{
		write_LCD_data(p[i+16]);
	}
}

11. IIC

同步串行通信,半双工

11.1 主机和从机

主机:产生时钟、起始信号和终止信号

从机:可编程的IIC地址检测,停止位检测

支持不同速率的通讯速度,标速(最高100kHz)、快速(400kHz)

11.2 SDA和SCL的数据传输

在这里插入图片描述

SDA:串行数据线 传输数据

SCL :串行时钟线 数据同步

SDA上在SCL的每个时钟周期传输一位数据

SDA上的数据传输 必须在SCL高电平时进行

SDA上的数据高低电平翻转 必须在SCL低电平时进行

每次传送一个字节(8位),先传送最高位

每一个被传送的字节后面必须跟一个应答位(共9位)

起始信号:SCL高电平,SDA高电平→低电平

终止信号:SCL高电平,SDA低电平→高电平

起始、终止信号均由主机发出,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态

11.3 基本代码

具体使用方法见 EEPROM 12.2/3

void IIC_Delay()		//前图中大于4us或4.7us的延时
{
	_nop_();_nop_();_nop_();
	_nop_();_nop_();_nop_();
}

void IIC_Init()			//将两根线拉高,进入初始状态,等待开始信号
{
	SDA = 1;
	SCL = 1;
}

void IIC_Start()		//起始信号,SCL为高时,SDA由高变低
{
	SCL = 1;
	SDA = 1;
	IIC_Delay();
	SDA = 0;
	IIC_Delay();
	SCL = 0;
	IIC_Delay();
}

void IIC_Stop()			//结束信号,SCL为高时,SDA由低变高
{
	SCL = 0;
	SDA = 0;
	IIC_Delay();
	SCL = 1;
	IIC_Delay();
	SDA = 1;
	IIC_Delay();
}

void IIC_ACK()			//应答信号
{
   unsigned char i=0;
   SCL = 1;			//SCL为高时,接收应答
   IIC_Delay();
   while((SDA==1)&&(i<255))		//过了一段时间SDA仍为高,就是非应答信号;否则,SDA=0,返回应答信号
   {  
       i++;
   }
   SCL = 0;			//应答后拉低时钟线,等待结束信号
   IIC_Delay();
}

void IIC_Write_Byte(unsigned char j)		//写一个字节,从高位到低位发送
{
	unsigned char i,temp;
	temp = j;
	SCL = 0;		//数据只在SCL为低时允许改变
	IIC_Delay();
	for(i=0;i<8;i++)
	{
		temp <<= 1;		//temp = temp << 1,从高到低依次移出
		SDA = CY;		//CY为PSW状态寄存器中的最高位,1000 0000<<1,CY=1;0000 0001>>1,CY=1.CY就是移出来的那一位
		IIC_Delay();
		SCL = 1;		//等待SDA数据稳定
		IIC_Delay();
		SCL = 0;		//等待下一次发送
		IIC_Delay();
	}
	SDA = 1;	
	IIC_Delay();
}

unsigned char IIC_Read_Byte()		//读一个字节,从低位到高位读
{
	unsigned char i,j,k=0;
	SCL = 0;		//拉低时钟线,等待数据变化
	IIC_Delay();
	for(i=0;i<8;i++)
	{
		SCL = 1;		//在这个时刻已经获取到了SDA的一位数据
		IIC_Delay();
		if(SDA == 1)
			j = 1;
		else 
			j = 0;
		k = (k<<1) | j;			//k依次往右移,最低位每次接受新的SDA 变化
		SCL = 0;		//等待下一次数据变化
	}
	return(k);		//返回读到的字节数据
}

12. EEPROM

采样IIC协议的接口与单片机相连,在proteus上可以体现出EEPROM的断点储存效果

下面的代码中IIC功能函数参考 IIC:11.3

12.1 器件地址

以24C02C为例:

在这里插入图片描述

高4位固定:1010 //不同类型器件高4位不同,由半导体公司生产时固定

低4位由A0、A1、A2和R/W(读/写位)决定 //用户可自定义

实际为7位地址,最后一位决定对EEPROM读或写

如图所示连接方式,地址为:1010 0000(0xa0),读数据时,地址为1010 0001(0xa1)

12.2 写数据

一次写一个字节,需要指定所写字节在EEPROM中的地址(24C02C储存数据最多为256个字节)

	IIC_Init();		//IIC初始化	
	//把数据写进EEPROM
	IIC_Start();			//IIC起始信号
	IIC_Write_Byte(0xa0);	//写器件地址	//0xa0:1010 0000
	IIC_ACK();				//应答
	//写第一个字节
	IIC_Write_Byte(0x00);	//写字节地址
	IIC_ACK();				//应答
	IIC_Write_Byte(0xfe);	//写数据
	IIC_ACK();				//应答
	//写第二个字节
	IIC_Write_Byte(0x01);	//写字节地址
	IIC_ACK();				//应答
	IIC_Write_Byte(0xfd);	//写数据
	IIC_ACK();				//应答
	//写第三个字节
	IIC_Write_Byte(0x02);	//写字节地址
	IIC_ACK();				//应答
	IIC_Write_Byte(0xfb);	//写数据
	IIC_ACK();				//应答
	
	IIC_Stop();				//结束信号

12.3 读数据

一次读一个字节,需要指定所读字节在EEPROM中的地址

	IIC_Init();		//IIC初始化	
	//从EEPROM读数据
	IIC_Start();			//IIC起始信号	
	IIC_Write_Byte(0xa0);	//写器件地址	//0xa0:1010 0000
	IIC_ACK();				//应答
	//读第一个字节
	IIC_Write_Byte(0x00);	//数据地址
	IIC_ACK();				//应答
	IIC_Start();			//IIC起始信号
	IIC_Write_Byte(0xa1);	//7位地址位,加上最低位读写位,允许读	//0xa1:1010 0001
	IIC_ACK();				//应答
	a = IIC_Read_Byte();	//读数据
	//读第二个字节
	IIC_Write_Byte(0x01);	//数据地址
	IIC_ACK();				//应答
	IIC_Start();			//IIC起始信号
	IIC_Write_Byte(0xa1);	//7位地址位,加上最低位读写位,允许读
	IIC_ACK();				//应答
	b = IIC_Read_Byte();	//读数据
	//读第三个字节
	IIC_Write_Byte(0x02);	//数据地址
	IIC_ACK();				//应答
	IIC_Start();			//IIC起始信号
	IIC_Write_Byte(0xa1);	//7位地址位,加上最低位读写位,允许读
	IIC_ACK();				//应答
	c = IIC_Read_Byte();	//读数据
	
	IIC_Stop();				//IIC结束信号

14. SPI

高速的,全双工,同步的通信总线

4根线:

  1. SDO – 主设备数据输出,从设备数据输入
  2. SDI – 主设备数据输入,从设备数据输出
  3. SCK – 时钟信号,由主设备产生
  4. CS – 从设备使能信号,由主设备控制

15. 位符操作 & |

15.1 基本概念

1&1=1 1&0=0 0&0=0

1|1=1 1|0=1 0|0=0

15.2 基本代码

    int n = 0x2d;	//0010 1101	45
    printf("原来的数为:%d\n",n);
    
	/*从右到左 -> IO口从上到下*/
	//修改n二进制数从右向左数第3位为1 -> 0010 1101	45
    int res = n|(1<<2);	
    printf("第3位改为1:%d\n",res);
	
	//修改n二进制数从右向左数第4位为0 -> 0010 0101	37
    int r2 = n&~(1<<3);
    printf("第4位改为0:%d\n",r2);
    
    //修改n二进制数从右向左数第5位为1 -> 0011 1101	61
    int r3 = n|(1<<4);	
    printf("第5位改为1:%d\n",r3);
    
    //修改n二进制数从右向左数第3位为0 -> 0010 0101	41
    int r4 = n&~(1<<2);
    printf("第3位改为0:%d\n",r4);

16. 位移操作 << >>

16.1 左移<<

i << j

i中所有的位向左移动j个位置,而右边填入0

16.2 右移>>

i中所有的位向右移j位

(1)对于unsigned类型,左边填入0

(2)对于signed类型,左边填入原来的最高位

所有小于int的类型,默认以int型操作

x <<= 1;	//等价于 x *= 2
x <<= n;	//等价于 x *= 2^n

x >>= 1;	//等价于 x /= 2
x >>= n;	//等价于 x /= 2^n
```c

ntf("第3位改为1:%d\n",res);
	
	//修改n二进制数从右向左数第4位为0 -> 0010 0101	37
    int r2 = n&~(1<<3);
    printf("第4位改为0:%d\n",r2);
    
    //修改n二进制数从右向左数第5位为1 -> 0011 1101	61
    int r3 = n|(1<<4);	
    printf("第5位改为1:%d\n",r3);
    
    //修改n二进制数从右向左数第3位为0 -> 0010 0101	41
    int r4 = n&~(1<<2);
    printf("第3位改为0:%d\n",r4);

16. 位移操作 << >>

16.1 左移<<

i << j

i中所有的位向左移动j个位置,而右边填入0

16.2 右移>>

i中所有的位向右移j位

(1)对于unsigned类型,左边填入0

(2)对于signed类型,左边填入原来的最高位

所有小于int的类型,默认以int型操作

x <<= 1;	//等价于 x *= 2
x <<= n;	//等价于 x *= 2^n

x >>= 1;	//等价于 x /= 2
x >>= n;	//等价于 x /= 2^n
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-06 09:59:50  更:2021-08-06 10:00:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:24:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码