问题描述
我原来使用Z-stack协议栈来读取BH1750光照传感器,获取环境光照数值。编写代码后,可以正常读取。
代码有BH1750.h、BH1750.c、iic.h、iic.h,如下
iic.h
#ifndef _IIC_H
#define _IIC_H
#include <ioCC2530.h>
typedef unsigned char u8;
#define IIC_SDA_OUTMODE() {P0DIR|=0x1<<1;}
#define IIC_SDA_INPUTMODE() {P0DIR&=~(0x1<<1);}
#define IIC_SDA_OUT P0_1 //数据线输出
#define IIC_SDA_IN P0_1 //数据线输入
#define IIC_SCL P0_0 //时钟线
void DelayUs(u8 t);
void IIC_Init(void);
void IIC_Start(void);
void IIC_Stop(void);
u8 IIC_GetACK(void);
void IIC_SendACK(u8 stat);
void IIC_WriteOneByteData(u8 data);
u8 IIC_ReadOneByteData(void);
#endif
iic.c
#include "iic.h"
#include "OnBoard.h"
/*
函数功能:IIC接口初始化
硬件连接:
SDA:P0.5
SCL:P0.4
*/
void DelayUs(u8 t)
{
MicroWait(t);
}
void IIC_Init(void)
{
P0SEL&=~(0x3<<3); //配置通用GPIO口模式
P0DIR|=0x3<<3; //配置为输出模式
}
/*
函数功能:IIC总线起始信号
*/
void IIC_Start(void)
{
IIC_SDA_OUTMODE(); //初始化SDA为输出模式
IIC_SDA_OUT=1; //数据线拉高
IIC_SCL=1; //时钟线 拉高
DelayUs(4); //电平保持时间
IIC_SDA_OUT=0; //数据线拉低
DelayUs(4); //电平保持时间
IIC_SCL=0; //时钟线拉低
}
/*
函数功能:IIC总线停止信号
*/
void IIC_Stop(void)
{
IIC_SDA_OUTMODE(); //初始化SDA为输出模式
IIC_SDA_OUT=0; //数据线拉低
IIC_SCL=0; //时钟线拉低
DelayUs(4); //电平保持时间
IIC_SCL=1; //时钟线拉高
DelayUs(4); //电平保持时间
IIC_SDA_OUT=1; //数据线拉高
}
/*
函数功能:获取应答信号
返 回 值:1表示失败,0表示成功
*/
u8 IIC_GetACK(void)
{
u8 cnt=0;
IIC_SDA_INPUTMODE();//初始化SDA为输入模式
IIC_SDA_OUT=1; //数据线上拉
DelayUs(2); //电平保持时间
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要数据
DelayUs(2); //电平保持时间,等待从机发送数据
IIC_SCL=1; //时钟线拉高,告诉从机,主机现在开始读取数据
while(IIC_SDA_IN) //等待从机应答信号
{
cnt++;
if(cnt>250)return 1;
}
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要数据
return 0;
}
/*
函数功能:主机向从机发送应答信号
函数形参:0表示应答,1表示非应答
*/
void IIC_SendACK(u8 stat)
{
IIC_SDA_OUTMODE(); //初始化SDA为输出模式
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要发送数据
if(stat)IIC_SDA_OUT=1; //数据线拉高,发送非应答信号
else IIC_SDA_OUT=0; //数据线拉低,发送应答信号
DelayUs(2); //电平保持时间,等待时钟线稳定
IIC_SCL=1; //时钟线拉高,告诉从机,主机数据发送完毕
DelayUs(2); //电平保持时间,等待从机接收数据
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要数据
}
/*
函数功能:IIC发送1个字节数据
函数形参:将要发送的数据
*/
void IIC_WriteOneByteData(u8 data)
{
u8 i;
IIC_SDA_OUTMODE(); //初始化SDA为输出模式
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要发送数据
for(i=0;i<8;i++)
{
if(data&0x80)IIC_SDA_OUT=1; //数据线拉高,发送1
else IIC_SDA_OUT=0; //数据线拉低,发送0
IIC_SCL=1; //时钟线拉高,告诉从机,主机数据发送完毕
DelayUs(2); //电平保持时间,等待从机接收数据
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要发送数据
DelayUs(2); //电平保持时间,等待时钟线稳定
data<<=1; //先发高位
}
}
/*
函数功能:IIC接收1个字节数据
返 回 值:收到的数据
*/
u8 IIC_ReadOneByteData(void)
{
u8 i,data;
IIC_SDA_INPUTMODE();//初始化SDA为输入模式
for(i=0;i<8;i++)
{
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要数据
DelayUs(2); //电平保持时间,等待从机发送数据
IIC_SCL=1; //时钟线拉高,告诉从机,主机现在正在读取数据
data<<=1;
if(IIC_SDA_IN)data|=0x01;
DelayUs(2); //电平保持时间,等待时钟线稳定
}
IIC_SCL=0; //时钟线拉低,告诉从机,主机需要数据 (必须拉低,否则将会识别为停止信号)
return data;
}
BH1750.h
#ifndef _BH1750_H
#define _BH1750_H
#include "iic.h"
#include <ioCC2530.h>
u8 Read_BH1750_Data(void);
#endif
BH1750.c
#include "bh1750.h"
#include "OnBoard.h"
u8 Read_BH1750_Data()
{ IIC_Init();
unsigned char t0;
unsigned char t1;
unsigned char t;
u8 r_s=0;
IIC_Start(); //发送起始信号
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:1\n",8); //(串口0,'字符',字符个数。)
IIC_WriteOneByteData(0x01);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:2\n",8); //(串口0,'字符',字符个数。)
IIC_Stop(); //停止信号
IIC_Start(); //发送起始信号
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:3\n",8); //(串口0,'字符',字符个数。)
IIC_WriteOneByteData(0x01);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:4\n",8); //(串口0,'字符',字符个数。)
IIC_Stop(); //停止信号
IIC_Start(); //发送起始信号
IIC_WriteOneByteData(0x46);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:5\n",8); //(串口0,'字符',字符个数。)
IIC_WriteOneByteData(0x10);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:6\n",8); //(串口0,'字符',字符个数。)
IIC_Stop(); //停止信号
IIC_Start(); //发送起始信号
IIC_WriteOneByteData(0x47);
r_s=IIC_GetACK();//获取应答
if(r_s)
HalUARTWrite(0,"error:7\n",8); //(串口0,'字符',字符个数。)
t0=IIC_ReadOneByteData(); //接收数据
IIC_SendACK(0); //发送应答信号
t1=IIC_ReadOneByteData(); //接收数据
IIC_SendACK(1); //发送非应答信号
IIC_Stop(); //停止信号
t=(((t0<<8)|t1)/1.2);
return t;
}
后来,遇到新的需求,要求将光照数据显示在IIC通信协议的OLED屏幕上;由于hal_lcd.c文件原来是SPI通信协议的,我对其重构为IIC通信协议的代码。
hal_lcd.c代码
/****************************************************************************
* Filename: hal_lcd.c
* Author: xiaoHuiHui
* Date: 2019-05-11
* Version: 1.0
* Description: OLED driver
****************************************************************************/
#include "hal_types.h"
#include "hal_lcd.h"
#include "OSAL.h"
#include "OnBoard.h"
#include "hal_assert.h"
#include <string.h>
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
#include "DebugTrace.h"
#endif
#define SCL P1_2 //串行时钟
#define SDA P1_3 //串行数据
#define XLevelL 0x00
#define XLevelH 0x10
#define XLevel ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xCF
#define X_WIDTH 128
#define Y_WIDTH 64
#define LCD_MAX_BUF 25
#define HAL_LCD_MAX_CHARS 16 // Max number of chars on a single LCD line
const unsigned char F8X16[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
#if (HAL_LCD == TRUE)
void HalLcd_HW_Init(void);
void HalLcd_HW_WaitUs(uint16 i);
void HalLcd_HW_Clear(void);
void HalLcd_HW_Control(uint8 cmd);
void HalLcd_HW_Write(uint8 data);
void HalLcd_HW_SetContrast(uint8 value);
void HalLcd_HW_WriteChar(uint8 line, uint8 col, char text);
void HalLcd_HW_WriteLine(uint8 line, const char *pText);
void DelayMS(unsigned int msec);
void LCD_DLY_ms(unsigned int ms);
void LCD_WrDat(unsigned char dat);
void LCD_WrCmd(unsigned char cmd);
void LCD_Set_Pos(unsigned char x, unsigned char y);
void LCD_Fill(unsigned char bmp_dat) ;
void LCD_CLS(void);
void LcdClearLine(unsigned char y, unsigned char count);
void LCD_P8x16Str(unsigned char x, unsigned char y,unsigned char ch[]);
void HalLcdDisplayPercentBar( char *title, uint8 value );
void LCD_P16x16Ch(unsigned char x, unsigned char y, unsigned char N);
#endif //LCD
/**************************************************************************************************
* @fn HalLcdInit
*
* @brief Initilize LCD Service
*
* @param init - pointer to void that contains the initialized value
*
* @return None
**************************************************************************************************/
void HalLcdInit(void)
{
#if (HAL_LCD == TRUE)
HalLcd_HW_Init();
#endif
}
/**************************************************************************************************
* @fn HalLcdWriteValue
*
* @brief Write a value to the LCD
*
* @param value - value that will be displayed
* radix - 8, 10, 16
* option - display options
*
* @return None
**************************************************************************************************/
void HalLcdWriteValue ( uint32 value, const uint8 radix, uint8 option)
{
#if (HAL_LCD == TRUE)
uint8 buf[LCD_MAX_BUF];
_ltoa( value, &buf[0], radix );
HalLcdWriteString( (char*)buf, option );
#endif
}
/**************************************************************************************************
* @fn HalLcdWriteScreen
*
* @brief Write a value to the LCD
*
* @param line1 - string that will be displayed on line 1
* line2 - string that will be displayed on line 2
*
* @return None
**************************************************************************************************/
void HalLcdWriteScreen( char *line1, char *line2 )
{
#if (HAL_LCD == TRUE)
HalLcdWriteString( line1, 1 );
HalLcdWriteString( line2, 2 );
#endif
}
/**************************************************************************************************
* @fn HalLcdWriteStringValue
*
* @brief Write a string followed by a value to the LCD
*
* @param title - Title that will be displayed before the value
* value - value
* format - redix
* line - line number
*
* @return None
**************************************************************************************************/
void HalLcdWriteStringValue( char *title, uint16 value, uint8 format, uint8 line )
{
#if (HAL_LCD == TRUE)
uint8 tmpLen;
uint8 buf[LCD_MAX_BUF];
uint32 err;
tmpLen = (uint8)osal_strlen( (char*)title );
osal_memcpy( buf, title, tmpLen );
//buf[tmpLen] = ' ';
err = (uint32)(value);
_ltoa( err, &buf[tmpLen], format );
HalLcdWriteString( (char*)buf, line );
#endif
}
/**************************************************************************************************
* @fn HalLcdWriteStringValue
*
* @brief Write a string followed by a value to the LCD
*
* @param title - Title that will be displayed before the value
* value1 - value #1
* format1 - redix of value #1
* value2 - value #2
* format2 - redix of value #2
* line - line number
*
* @return None
**************************************************************************************************/
void HalLcdWriteStringValueValue( char *title, uint16 value1, uint8 format1,
uint16 value2, uint8 format2, uint8 line )
{
#if (HAL_LCD == TRUE)
uint8 tmpLen;
uint8 buf[LCD_MAX_BUF];
uint32 err;
tmpLen = (uint8)osal_strlen( (char*)title );
if ( tmpLen )
{
osal_memcpy( buf, title, tmpLen );
//buf[tmpLen++] = ' ';
}
err = (uint32)(value1);
_ltoa( err, &buf[tmpLen], format1 );
tmpLen = (uint8)osal_strlen( (char*)buf );
buf[tmpLen++] = ',';
buf[tmpLen++] = ' ';
err = (uint32)(value2);
_ltoa( err, &buf[tmpLen], format2 );
HalLcdWriteString( (char *)buf, line );
#endif
}
#if (HAL_LCD == TRUE)
void DelayMS(unsigned int msec)
{
unsigned int i,j;
for (i=0; i<msec; i++)
for (j=0; j<530; j++);
}
/*********************LCD 延时1ms************************************/
void LCD_DLY_ms(unsigned int ms)
{
unsigned int a;
while(ms)
{
a=1800;
while(a--);
ms--;
}
return;
}
/**********************************************
//IIC Start
**********************************************/
void IIC_start()
{
SCL = 1;
SDA = 1;
asm("NOP");
asm("NOP");
SDA = 0;
asm("NOP");
asm("NOP");
SCL = 0;
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_stop()
{
SCL = 0;
SDA = 0;
asm("NOP");
asm("NOP");
SCL = 1;
SDA = 1;
asm("NOP");
asm("NOP");
}
/**********************************************
// 通过I2C总线写一个字节
**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(IIC_Byte & 0x80)
SDA=1;
else
SDA=0;
asm("NOP");
asm("NOP");
SCL=1;
asm("NOP");
asm("NOP");
SCL=0;
IIC_Byte<<=1;
}
SDA=1;
asm("NOP");
asm("NOP");
SCL=1;
asm("NOP");
asm("NOP");
SCL=0;
asm("NOP");
asm("NOP");
}
/*********************LCD写数据************************************/
void LCD_WrDat(unsigned char dat)
{
IIC_start();
Write_IIC_Byte(0x78);
Write_IIC_Byte(0x40); //write data
Write_IIC_Byte(dat);
IIC_stop();
}
/*********************LCD写命令************************************/
void LCD_WrCmd(unsigned char cmd)
{
IIC_start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
Write_IIC_Byte(0x00); //write command
Write_IIC_Byte(cmd);
IIC_stop();
}
/*********************LCD 设置坐标************************************/
void LCD_Set_Pos(unsigned char x, unsigned char y)
{
LCD_WrCmd(0xb0+y);
LCD_WrCmd(((x&0xf0)>>4)|0x10);
LCD_WrCmd((x&0x0f)|0x01);
}
/*********************LCD全屏************************************/
void LCD_Fill(unsigned char bmp_dat)
{
unsigned char y,x;
for(y=0;y<8;y++)
{
LCD_WrCmd(0xb0+y);
LCD_WrCmd(0x01);
LCD_WrCmd(0x10);
for(x=0;x<X_WIDTH;x++)
LCD_WrDat(bmp_dat);
}
}
/*********************LCD复位************************************/
void LCD_CLS(void)
{
unsigned char y,x;
for(y=0;y<8;y++)
{
LCD_WrCmd(0xb0+y);
LCD_WrCmd(0x01);
LCD_WrCmd(0x10);
for(x=0;x<X_WIDTH;x++)
LCD_WrDat(0);
}
}
void LcdClearLine(unsigned char y, unsigned char count)
{
unsigned char x,j;
for(j=y; j<(y+count); j++)
{
LCD_WrCmd(0xb0+j);
LCD_WrCmd(0x01);
LCD_WrCmd(0x10);
for(x=0;x<X_WIDTH;x++)
LCD_WrDat(0);
}
}
void HalLcdWriteString (char *str, uint8 option)
{
uint8 x=0,y=0,strLen;
uint8 lcdBuf[HAL_LCD_MAX_CHARS+1];
x=0;
y = (option-1)*2;
strLen = (uint8)osal_strlen( (char*)str );
/* Check boundries */
if ( strLen > HAL_LCD_MAX_CHARS )
strLen = HAL_LCD_MAX_CHARS;
osal_memset(lcdBuf, 0, HAL_LCD_MAX_CHARS+1);
osal_memcpy( lcdBuf, str, strLen );
LcdClearLine(y, 2);
LCD_P8x16Str(x, y, lcdBuf);
}
/***能描述:显示8*16一组标准ASCII字符串 显示的坐标(x,y),y为页范围0~7***/
void LCD_P8x16Str(unsigned char x, unsigned char y,unsigned char ch[])
{
unsigned char c=0,i=0,j=0;
while (ch[j]!='\0')
{
c =ch[j]-32;
if(x>120){
x=0;
y++;
}
LCD_Set_Pos(x,y);
for(i=0;i<8;i++)
LCD_WrDat(F8X16[c*16+i]);
LCD_Set_Pos(x,y+1);
for(i=0;i<8;i++)
LCD_WrDat(F8X16[c*16+i+8]);
x+=8;
j++;
}
}
void HalLcd_HW_WaitUs(uint16 microSecs)
{
while(microSecs--)
{
/* 32 NOPs == 1 usecs */
asm("nop"); asm("nop"); asm("nop"); asm("nop");
asm("nop"); asm("nop"); asm("nop"); asm("nop");
}
}
void HalLcd_HW_Init(void)
{
P1SEL &= 0xF3;
P1DIR |= 0x0C; //P05、P06定义为输出
LCD_DLY_ms(50);
LCD_WrCmd(0xae);//--turn off oled panel
LCD_WrCmd(0x00);//---set low column address
LCD_WrCmd(0x10);//---set high column address
LCD_WrCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
LCD_WrCmd(0x81);//--set contrast control register
LCD_WrCmd(Brightness); // Set SEG Output Current Brightness
LCD_WrCmd(0xa1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
LCD_WrCmd(0xc8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
LCD_WrCmd(0xa6);//--set normal display
LCD_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
LCD_WrCmd(0x3f);//--1/64 duty
LCD_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
LCD_WrCmd(0x00);//-not offset
LCD_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
LCD_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
LCD_WrCmd(0xd9);//--set pre-charge period
LCD_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
LCD_WrCmd(0xda);//--set com pins hardware configuration
LCD_WrCmd(0x12);
LCD_WrCmd(0xdb);//--set vcomh
LCD_WrCmd(0x40);//Set VCOM Deselect Level
LCD_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
LCD_WrCmd(0x02);//
LCD_WrCmd(0x8d);//--set Charge Pump enable/disable
LCD_WrCmd(0x14);//--set(0x10) disable
LCD_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
LCD_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)
LCD_WrCmd(0xaf);//--turn on oled panel
LCD_Fill(0x00); //初始清屏
LCD_Set_Pos(0,0);
}
#endif
重新烧录之后,OLED能够正常显示,但是无法读取BH1750光照强度了。我也没有改BH1750的代码,为什么会出现这种情况?