单片机实训(2021/7/8~2021/7/16)第二天

前面的话

几经波折,来到这里的第二天晚上遇到了超级大雨,停电了。。。
现在一切恢复正常,把前几天的记录都补回来。

今日内容

实现了用数码管显示数字,并用按键来控制加减。

所用器件

1、51单片机(带四个按键)(STC15W4K56S4_LQFP64)
在这里插入图片描述
在这里插入图片描述

2、四位显示数码管
在这里插入图片描述

所需基础知识

1、如何代码实现按键加减
2、tm1650数码管驱动显示(LED驱动专用电路)
3、I2C通信协议

TM1650数码管驱动(一)

电路原理图

在这里插入图片描述

驱动介绍

(笔者是根据TM1650的开发手册来进行学习的,这里也是用该手册来进行介绍。)
想要看开发手册可以点击这里:戳这儿
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过时序格式以及引脚可以看出tm1650驱动使用的I2C通信协议。

I2C协议

I2C协议简介

IIC通讯协议(Inter----Integrted Circuit)是由Phiips飞利浦公司开发的,由于他引脚少,硬件实现简单,可拓展性强,不需要UASRT,CAN通讯协议的外部收发设备,现在被广泛使用在系统内多个集成电路IC(芯片)间的通讯。

半双工的通讯方式

在这里插入图片描述

IIC总线系统结构

在这里插入图片描述
他是一个支持多设备的总线。”总线”指多个设备共用的信号线,在一个IIC通讯总线中,可连接多个IIC通讯设备,支持多个通讯主机及多个通讯从机。
一个IIC总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备直接的访问。

IIC总线物理层特点

在这里插入图片描述

总线通过上拉电阻接到电源。当IIC设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态,由上拉电阻把总线拉成高电平。
多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定哪个设备占用总线。
具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4M/s,但目前大多IIC设备尚不支持高速模式。

IIC总线协议层

IIC协议层
IIC的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节

主机写数据到从机

在这里插入图片描述
在这里插入图片描述
S:数据由主机传输至从机
在这里插入图片描述

P:数据传输结束
在这里插入图片描述
SLAVE ADDRESS : 从机地址

起始信号产生后,所有从机就开始紧接下来广播的从机地址信号。IIC总线,每个设备的地址都是唯一的,当主机广播的地址与某个设备的地址相同时,这个设备就被选中了,没被选中的设备讲会忽略之后的数据信号。根据IIC协议,这个从机地址可以是7位或10位。
在这里插入图片描述

地址位之后,传输方向选择位,为0:表示数据传输方向是由主机传输至从机,即主机向从机写数据。为1:则相反。从机接收传输方向选择位后,主机或从机会返回一个应答(ACK)信号
在这里插入图片描述
或非应答(NACK)信号,
在这里插入图片描述
只有接收到应答信号后,主机才能继续发送或接收数据。

主机读数据到从机

在这里插入图片描述

读数据:
配置方向传输位为”读数据”方向。广播完地址后,接收到应答信号后,从机开始向主机返回数据(DATA),数据包大小也为8位,从机每发送完一个数,都会等待主机的应答信号(ACK),重复这个过程,可以返回N个数据,N没有限制大小。当主机希望停止接收数据时,就向从机返回一个非应答信号(NCAK),则从机自动停止数据传输。

通讯复合格式

在这里插入图片描述
复合格式,该传输过程有两次起始信号(S),在第一次传输过程中,主机通过SLAVE_ADDRESS寻找到从设备后,发送一段”数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址;第二次传输中,对该地址的内容进行读或写。也就是说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。

I2C通信的六点注意

① 空闲状态
②开始信号
③停止信号
④应答信号
⑤数据的有效性
⑥数据传输

①空闲信号

IIC总线的SDA和SCL两条信号线同时处于高电平时,规定位总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

②开始信号 、③停止信号

起始信号:当SCL为高电平期间,SDA有高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
停止信号:当SCL为高电平期间,SDA由低到高的跳变;停止信号也是一种高电平跳变时序信号,而不是一个电平信号
起始信号和停止信号一般由主机产生
在这里插入图片描述

④应答信号

发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位)表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
对于反馈有效应答位ACK的要求是,接收器在第九个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。
如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
在这里插入图片描述

⑤数据的有效性

IIC总线进行数据传输时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。SDA数据线在SCL的每个时钟周期传输一位数据。

即:数据在SCL的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定
在这里插入图片描述

⑥数据传输

在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

TM1650数码管驱动(二)

TM1650 时序图

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

操作指令集[(系统/按键)/ 亮度 ]

在这里插入图片描述

四位数码管地址与八位led灯的显示

在这里插入图片描述

操作流程图

在这里插入图片描述

代码

必要的知识内容已经讲完,下面开始上代码!!

头文件

#include<STC15F2K60S2.h>	
#include<intrins.h>

对数据类型进行定义

#define uchar unsigned char //对数据类型进行声明定义
#define uint  unsigned int

定义数码管驱动引脚 以及按键

sbit CLK = P7^0;    //时钟线
sbit DIO = P7^1;    //数据线
//TM1650管脚的定义声明
sbit k1=P6^0;	 //定义P60口是k1
sbit k2=P6^1;	 //定义P61口是k2
sbit k3=P6^2;	 //定义P62口是k3
sbit k4=P6^3;	 //定义P62口是k3
sbit led=P5^5;	 //定义P55口是led
//四个按键 以及 led显示灯的定义声明

宏定义时钟线、数据线的电平操作

#define CLK_H  CLK = 1;
#define CLK_L  CLK = 0;

#define DIO_H  DIO = 1;
#define DIO_L  DIO = 0;

函数声明

void TM1650_Set(uchar add,uchar dat);//函数声明
uchar Scan_Key(void);
void Delay_us(uint i);
uchar z=0;
uchar i,j;
uchar flag=0;

uchar code CODE[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0xff,0x6f}; 

延时函数

/*********************************************************
* 函 数 名         : Delay_us
* 函数功能		   : 延时函数,i=1时,大约延时10us
*********************************************************/
void Delay_us(uint i) 
{
for(;i>0;i--)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}

数码管驱动 I2C时序 开始函数

/*********************************************************
* 函 数 名         : I2CStart
* 函数功能		     : I2C起始函数
*********************************************************/
void I2CStart(void)
{
CLK_H;
DIO_H;
Delay_us(5);
DIO_L;

}

数码管驱动 I2C时序 应答函数

/*****************************************************
* 函 数 名         : I2CCask
* 函数功能		   : I2C确认函数
*****************************************************/
void I2Cask(void) 
{
uchar timeout = 1;
CLK_H;
Delay_us(5);
CLK_L;
while((DIO)&&(timeout<=100))
{
  timeout++;
}
Delay_us(5);
CLK_L;
}

数码管驱动 I2C时序 停止函数

/*************************************************************
* 函 数 名         : I2CStop
* 函数功能		   : I2C停止函数
*************************************************************/
void I2CStop(void) 
{
CLK_H;
DIO_L;
Delay_us(5);
DIO_H;
}

数码管驱动 I2C时序 写数据函数

/*************************************************
* 函 数 名      : I2CWrByte
* 函数功能		 : 写字节函数
* 输    入       : 一个字节
* 输    出    	 : 无
************************************************/
void I2CWrByte(uchar oneByte) 
{
uchar i;
CLK_L;
Delay_us(1);
for(i=0;i<8;i++)
{
oneByte = oneByte<<1;
DIO = CY;
CLK_L;
Delay_us(5);
CLK_H;
Delay_us(5);
CLK_L;
}
}

数码管驱动 向指定地址传入数据

/*******************************************************
* 函 数 名       : TM1650_Set
* 函数功能		   : 向指定地址写入数据函数
* 输    入       : add  写入的地址;dat  要写入的数据
* 输    出    	 : 无
*******************************************************/
void TM1650_Set(uchar add,uchar dat) 
{
I2CStart();
I2CWrByte(add); 
I2Cask();
I2CWrByte(dat);
I2Cask();
I2CStop();
}

按键函数

/*******************************************************
* 函 数 名         : keypros
* 函数功能		   : 按键处理函数,判断按键K1是否按下
********************************************************/
void keypros()
{
	
	
	if(k3==0)
	{
		Delay_us(100);   //消除抖动 一般大约10ms
		if(k3==0)
		{
			flag=1;				//led状态取反
//			led=~led;
		}
		while(!k3);	 //检测按键是否松开
	}
	if(k4==0)
	{
		Delay_us(1000);   //消除抖动 一般大约10ms
		if(k4==0)
		{
			flag=0;				//led状态取反
//			led=~led;
		}
		while(!k4);	 //检测按键是否松开
	}
	
	if(flag==1)
	{
		
		if(k1==0)		  //检测按键K1是否按下
	     {	
		   Delay_us(1000);   //消除抖动 一般大约10ms
		   if(k1==0&&z<99)	     //再次判断按键是否按下
		   {
//			 led=~led;				//led状态取反
			 z++;		 
		   }		
		  TM1650_Set(0x68,CODE[z/10]);
		  TM1650_Set(0x6a,CODE[z%10]);
		  while(!k1);	 //检测按键是否松开
	    }
	  if(k2==0)		  //检测按键K1是否按下
	   {	
		 Delay_us(1000);   //消除抖动 一般大约10ms
		 if(k2==0&&z>0)	     //再次判断按键是否按下
		  {
//			led=~led;				//led状态取反
			z--; 
		  }
		  
		TM1650_Set(0x68,CODE[z/10]);
		TM1650_Set(0x6a,CODE[z%10]);
		 while(!k2);	 //检测按键是否松开 
	   }	
	}
    if(flag==0)
	{
		
		TM1650_Set(0x48,0x51);
		TM1650_Set(0x68,CODE[0]);
		TM1650_Set(0x6a,CODE[0]);    		 
    }	
   	
	
}

main函数

/*******************************************************
* 函 数 名       : main
* 函数功能		   : 主函数
* 输    入       : 无
* 输    出    	 : 无
********************************************************/


void main()
{

    flag=0;
    while(1)
	{		
		keypros();		
		}
}

写在最后

”行胜于言“

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值