从GPIO实现控制LED发光二极管开始说起之三

前述两节主要讨论GPIO端口的一般使用方法,本节讨论GPIO的另一个常用用途:总线模拟。

嵌入式系统应用场合是多种多样的,需要的设备也是多种多样,而微控制器本身提供的设备一定是有限的,而设备本身和MCU之间的通讯方式也是各有不同,在这种情况下我们就可以考虑用GPIO模拟设备与MCU之间的接口。

目前比较典型的有采用74HC594实现串转并功能、DS18B20实现单总线功能、SPI总线功能等

1.采用74HC595实现串转并功能

在第一节中我们利用8个管脚实现了流水灯功能,但是我们也可以看到每一个LED占据一条口线,而系统的口线资源是非常宝贵的,74HC595是带输出锁存的8位移位寄存器,其内部结构如下:

其控制端口:

1)SH_CP(11脚):移位时钟脉冲输入端。在上升沿时移位寄存器将数据移位

2)DS(14脚):串行数据输入端。通过移位运算将每次移位的数据值传递给DS引脚,8次移位后完成一个字符的串行传送。

3)ST_CP(12脚):锁存脉冲控制端,在上升沿时移位寄存器的数据被传入存储寄存器,这时如果OE端为低电平,传入存储器的数据会直接输出到输出端Q0-Q7。在一个字节的移位操作完成后,通过在ST_CP端产生一个上升沿将数据送出。

4)/MR(10脚):低电平时将移位寄存器数据请0.一般情况下接VCC

5)/OE(13脚):高电平时输出端禁止输出(高阻态)。低电平时允许数据输出

(吐槽一下:74HC595的datasheet和proteus中的管脚名称不知为什么不一致,头疼)

#include"reg51.h"
#include"intrins.h"
sbit SH_CP=P2^0;//输入时钟信号口
sbit DS=P2^1;   //数据输入口
sbit ST_CP=P2^2;//数据输出锁存口
void sendOneByte(unsigned char msg){
 unsigned char i;
 ST_CP=0;//为上升沿信号,将1byte数据锁存输出

 for(i=0;i<8;i++){//将一个字节的8位从高到低一位一位的输出
   SH_CP=0;//先是低电平
   DS=msg>>7;
   msg<<=1;
   SH_CP=1;//然后是高电平,产生上升沿信号,将1bit数据输出

   _nop_();//延迟一段时间
   _nop_();
 }

 ST_CP=1;//上升沿信号,将1byte数据锁存输出
 _nop_();//延迟一段时间
 _nop_();


}
#include"74hc595.h"
unsigned char code pattern[]={1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7};
extern void sendOneByte(unsigned char msg);
void delay(int t){
   while(--t);
}
void main(){
   unsigned char i=0;
   while(1){
     for(i=0;i<8;i++){
       sendOneByte(pattern[i]);
       delay(5000);
       sendOneByte(0xFF);
       delay(5000);
     }
   }
}

2.DS18B20

DS18B20是所谓的单总线数字式温度传感器,一般MCU并不支持单总线,这时候就需要考虑用GPIO口线模拟单总线。DS18B20单总线原理在此不必详述了,关于它的资料网上有很多(链接:https://pan.baidu.com/s/11iNJ3YNRfl-a7qyqDC8szQ 提取码:gfqr )。模拟单总线的关键难点在于时间及时序的准确控制。

 DS18B20的驱动如下:

/*
注意:晶振为12MHZ
*/
#include"reg51.h"
#include<intrins.h>
sbit DQ=P2^0;
extern void delay_ms(int num);
void Init_DS18B20(void){//初始化ds18b20
  DQ = 1;//DQ复位
  delay_ms(8);//稍做延时
  DQ = 0;//单片机将DQ拉低
  delay_ms(80);//精确延时大于480us
  DQ = 1;//拉高总线
  delay_ms(14);
  delay_ms(20);
}
unsigned char ReadOneChar(void){//读一个字节,从低位到高位
  unsigned char i=0;
  unsigned char dat = 0;
  for (i=8;i>0;i--){
	DQ = 0; // 将总线拉低,给脉冲信号
	dat>>=1;//做一个小小的延迟,并为下一位数据接收做准备
	DQ = 1; // 释放总线,给脉冲信号,上拉电阻会将总线拉低,或DS18B20将总线拉低
	if(DQ)//总线是否被dS18B20拉低,拉低则为0,否则为高
	  dat|=0x80;
	delay_ms(4);
  }
  return(dat);
}
void WriteOneChar(unsigned char dat){//写一个字节,从低位到高位一位一位输出
  unsigned char i=0;
  for (i=8; i>0; i--){
	DQ = 0;
	DQ = dat&0x01;
	delay_ms(5);
	DQ = 1;
	dat>>=1;
  }
}
//返回值是温度值的补码,有效位数为12位
//最高位为1时表示为负值
unsigned int ReadTemperature(void){//读取温度
  unsigned char tml=0;//温度值的低字节
  unsigned char tmh=0;//温度值的高字节
  unsigned int tvalue;//温度值补码
  Init_DS18B20();
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0x44);//转换温度,这时温度值才能保存在存储区
  Init_DS18B20();
  WriteOneChar(0xCC);
  WriteOneChar(0xBE); //读取温度寄存器
  tml=ReadOneChar();//读低8位
  tmh=ReadOneChar();//读高8位
  tvalue=tmh;
  tvalue<<=8;
  tvalue|=tml;
	
  return tvalue;
  //tvalue=tvalue*0.0625;//读取的数据保留到个位
	
}

*将DS18B20的温度值转换为浮点数 

//正数的补码是原码
//负数的补码是负数的绝对值的原码按位取反加1
//将DS18B20的12位温度值转换为浮点数
float u16ToFloat(u16 dat){
   float result=0.0; 
   u8 tmh=(dat&0xFF00)>>8;
   result=tmh>7?(~(dat-1)) *(-1.0):dat;
   return result*0.00625;
}

数码管的驱动如下:

#include"reg51.h"
#include<intrins.h>
#define Segment P1
#define Position P3
extern void delay_ms(int num);
static unsigned char code _Table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsigned char _buff[]={0,0,0,0,0,0,0,0};//显示缓冲区
static unsigned char code _Pos[]={1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7};
static unsigned char pos=0;//显示的位置
void display(){
  Segment=0xFF;
  Segment=_Table[_buff[pos]]; 
  Position=_Pos[pos];
  delay_ms(1);
			
  pos++;
  if(8==pos)
	pos=0;
}

应用程序如下: 

#include"ds18b20.h"
#include"display.h"
void delay_ms(int num){ //延时函数
  while(num--);
}
void main(){
  unsigned int tmp=0;
  while(1){
    tmp=ReadTemperature();
    _buff[3]=(tmp/10000)%10;
    _buff[4]=(tmp/1000)%10;
    _buff[5]=(tmp/100)%10;
    _buff[6]=(tmp/10)%10;
    _buff[7]=tmp%10;
    display();
  }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值