第一部分:BH1750光强模块代码头文件(BH1750.h)
#ifndef BH1750_H
#define BH1750_H
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
//IIC总线地址接口定义
#define IIC_SCL PBout(3)
#define IIC_SDA_OUT PAout(15)
#define IIC_SDA_IN PAin(15)
#define IIC_INPUT_MODE_SET() {GPIOA->CRH&=0x0FFFFFFF;GPIOA->CRH|=0x80000000;}
#define IIC_OUTPUT_MODE_SET() {GPIOA->CRH&=0x0FFFFFFF;GPIOA->CRH|=0x30000000;}
#define IIC_WRITE 0 // 写
#define IIC_READ 1 // 读
#define SlaveAddress 0x46 //BH1750地址
extern u8 BUF[3];
//函数声明
void IIC_Init(void);
void BH1750_Start();
void BH1750_Stop();
void BH1750_SendACK(char ack);
char BH1750_RecvACK();
void BH1750_SendByte(u8 data);
void Single_Write_BH1750(u8 REG_Address);
void Multiple_Read_BH1750();
void Get_Sunlight_Value();
u8 BH1750_RecvByte();
#endif
第二部分:BH1750光强模块代码文件(BH1750.c)
#include "BH1750.h"
/*
函数功能: IIC总线初始化
硬件连接:
SCL-PB3
SDA-PA15
*/
u8 BUF[3];
void IIC_Init(void)
{
/*1. 开时钟*/
RCC->APB2ENR|=1<<2; //PA
RCC->APB2ENR|=1<<3; //PB
RCC->APB2ENR|=1<<0; //开启AFIO时钟
/*2. 配置模式*/
AFIO->MAPR |= 0x2<<24;//关闭JTAG-DP,启用SW-DP
GPIOA->CRH&=0x0FFFFFFF;
GPIOA->CRH|=0x30000000;
GPIOB->CRL&=0xFFFF0FFF;
GPIOB->CRL|=0x00003000;
/*3. 上拉*/
GPIOA->ODR|=0x1<<15;
GPIOB->ODR|=0x1<<3;
//printf("BH1750 IIC_Init OK! \n");
}
/**************************************
起始信号
**************************************/
void BH1750_Start()
{
IIC_OUTPUT_MODE_SET(); //配置输出模式
IIC_SDA_OUT = 1; //拉高数据线
IIC_SCL = 1; //拉高时钟线
DelayUs(5); //延时
IIC_SDA_OUT = 0; //产生下降沿
DelayUs(5); //延时
IIC_SCL = 0; //拉低时钟线
}
/*
函数功能: 停止信号
*/
void BH1750_Stop()
{
IIC_OUTPUT_MODE_SET(); //配置输出模式
IIC_SDA_OUT = 0; //拉低数据线
IIC_SCL = 1; //拉高时钟线
DelayUs(5); //延时
IIC_SDA_OUT = 1; //产生上升沿
DelayUs(5); //延时
}
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void BH1750_SendACK(char ack)
{
IIC_OUTPUT_MODE_SET(); //配置输出模式
IIC_SCL = 0; //拉低时钟线
if(ack) IIC_SDA_OUT = 1;
else IIC_SDA_OUT = 0; //写应答信号
DelayUs(2); //延时
IIC_SCL = 1; //拉高时钟线
DelayUs(5); //延时
IIC_SCL = 0; //拉低时钟线
}
/**************************************
接收应答信号
**************************************/
char BH1750_RecvACK()
{
u8 cnt=0;
IIC_INPUT_MODE_SET();//输入模式
IIC_SDA_OUT=1;
DelayUs(1);
IIC_SCL=1;
DelayUs(1);
while(IIC_SDA_IN)//等待应答
{
cnt++;
DelayUs(1);
if(cnt>=250)//等待时间过长,产生停止信号,返回1,表示接收应答失败
{
BH1750_Stop();
//printf("N0 ACK\n");
return 1;
}
}
IIC_SCL=0;//应答成功,则SCL变低
return 0;
}
/**************************************
向IIC总线发送一个字节数据
**************************************/
void BH1750_SendByte(u8 data)
{
u8 i;
IIC_OUTPUT_MODE_SET();
IIC_SCL = 0;//拉低时钟线, 数据准备发送
DelayUs(2);//延时
for (i=0;i<8;i++)//从高位开始一位一位地传送
{
if(data&0x80) IIC_SDA_OUT=1;//送数据口
else IIC_SDA_OUT=0;
data <<= 1;//移出数据的最高位
IIC_SCL = 1; //拉高时钟线,发送数据
DelayUs(2);//延时
IIC_SCL = 0;//拉低时钟线,数据发送完毕
DelayUs(2);//延时
}
}
/**************************************
从IIC总线接收一个字节数据
**************************************/
u8 BH1750_RecvByte()
{
u8 i;
u8 data = 0;
IIC_INPUT_MODE_SET();//使能内部上拉,准备读取数据,
for (i=0;i<8;i++)//8位计数器
{
IIC_SCL=0;//置时钟线为低,准备接收数据位
DelayUs(2);//时钟低电平周期大于4.7μs
IIC_SCL=1;//置时钟线为高使数据线上数据有效,主机开始读数据,从机不能再改变数据了,即改变SDA的电平
data <<= 1;
IIC_SCL = 1;//拉高时钟线
if(IIC_SDA_IN) data|=0x01;//读数据
DelayUs(1);//延时
}
IIC_SCL=0;
return data;
}
void Single_Write_BH1750(u8 REG_Address)
{
BH1750_Start();//起始信号
BH1750_SendByte(SlaveAddress);//发送设备地址+写信号
BH1750_RecvACK();
BH1750_SendByte(REG_Address);//内部寄存器地址,请参考中文pdf22页
BH1750_RecvACK();
BH1750_Stop();//发送停止信号
}
/*********************************************************
连续读出BH1750内部数据
*********************************************************/
void Multiple_Read_BH1750()
{
BH1750_Start();//起始信号
BH1750_SendByte(SlaveAddress+1);//发送设备地址+读信号
BH1750_RecvACK();
BUF[0] = BH1750_RecvByte();//BUF[0]存储0x32地址中的数据
BH1750_SendACK(0);
BUF[1] = BH1750_RecvByte();//BUF[0]存储0x32地址中的数据
BH1750_SendACK(1);
BH1750_Stop();//停止信号
DelayMs(5);
}
/*********************************************************
读出数据并合成实际光强值
*********************************************************/
void Get_Sunlight_Value()
{
int dis_data=0;
float temp;
u8 i=0;
Single_Write_BH1750(0x01);// power on
Single_Write_BH1750(0x10);// H- resolution mode
DelayMs(180);//延时180ms
Multiple_Read_BH1750();//连续读出数据,存储在BUF中
for(i=0;i<3;i++)
//printf("0X%X ",BUF[i]);
dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1];//合成数据
temp=(float)dis_data/1.2;
printf("Sunlight=%0.2f lx\n",temp);
}
第三部分:主函数(main.c)
#include "stm32f10x.h"
#include "config.h"
#include "usart.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"
#include "BH1750.h"
int main(void)
{
u8 i=0;
USARTx_Init(USART1,72,115200);
TIMERx_Init(TIM1,72,20000); //辅助串口1接收。20ms为一帧数据。
IIC_Init();//BH1750初始化
while(1)
{
Get_Sunlight_Value();//获取光照强度值
DelayMs(2000);
}
}
第四部分:USARTx_Init(USART1,72,115200);//printf串口打印
void USARTx_Init(USART_TypeDef *USARTx,int clock,int baud)
{
if(USARTx==USART1)
{
/*1.开总线GPIOA的时钟*/
RCC->APB2ENR |= 1<<2;
/*2.设置GPIOA口模式 PA9--TX(1011) PA10--RX(1000)*/
GPIOA->CRH &= 0xFFFFF00F;
GPIOA->CRH |= 0x000008B0;
/*3.开USART1时钟*/
RCC->APB2ENR |= 1<<14;//使能USART1
RCC->APB1RSTR |= 1<<14;//开启复位USART1
RCC->APB1RSTR &= ~(1<<14);//关闭复位USART1
/*4.设置USARTx中断 */
#ifdef USART1_IRQ_RX
USART1->CR1|=1<<5; //开启串口接收中断
STM32_NVIC_SetPriority(USART1_IRQn,0,0); //优先级设置
#endif
}
else if(USARTx==USART2)
{
/*1.开总线GPIOA的时钟*/
RCC->APB2ENR |= 1<<2;
/*2.设置GPIOA口模式 PA2--TX(1011) PA3--RX(1000)*/
GPIOA->CRL &= 0xFFFF00FF;
GPIOA->CRL |= 0x00008B00;
/*3.开USART2时钟*/
RCC->APB1ENR |= 1<<17;//使能USART2
RCC->APB1RSTR |= 1<<17;//开启复位USART2
RCC->APB1RSTR &= ~(1<<17);//关闭复位USART2
/*4.设置USARTx中断 */
#ifdef USART2_IRQ_RX
USART2->CR1|=1<<5; //开启串口接收中断
STM32_NVIC_SetPriority(USART2_IRQn,1,0); //优先级设置
#endif
}
else if(USARTx==USART3)
{
/*1.开总线GPIOB的时钟*/
RCC->APB2ENR |= 1<<3;
/*2.设置GPIOB口模式 PB10--TX(1011) PB11--RX(1000)*/
GPIOB->CRH &= 0xFFFF00FF;
GPIOB->CRH |= 0x00008B00;
/*3.开USART3时钟*/
RCC->APB1ENR |= 1<<18;//使能USART3
RCC->APB1RSTR |= 1<<18;//开启复位USART3
RCC->APB1RSTR &= ~(1<<18);//关闭复位USART3
/*4.设置USARTx中断 */
#ifdef USART3_IRQ_RX
USART3->CR1|=1<<5; //开启串口接收中断
STM32_NVIC_SetPriority(USART3_IRQn,2,0); //优先级设置
#endif
}
else
{
printf("%s串口参数错误!!!\n","USARTx");
return ;
}
/*5.设置USARTx波特率*/
USARTx->BRR = clock*1000000/baud; //brr=clock/baud
/*6.设置USARTx控制寄存器 */
USARTx->CR1 |= 1<<2;//使能接收
USARTx->CR1 |= 1<<3;//使能发送
USARTx->CR1 |= 1<<13;//USARTx模块使能
}
第五部分:printf重定向函数
/********************************
将标准输入输出重定向到USART1
********************************/
int fputc(int c ,FILE *stream)
{
USART1->DR = c;
while(!(USART1->SR&1<<7));//等待数据发送完成
return c;
}
int fgetc(FILE *stream)
{
while(!(USART1->SR&1<<5));//等待数据
return USART1->DR;
}
第六部分:初始化定时器 TIMERx_Init(TIM1,720,10000);
/*函数功能: 初始化定时器
函数形参:
u32 psc :预分频系数
u32 arr :重装载计数器*/
void TIMERx_Init(TIM_TypeDef *TIMx,u32 psc,u32 arr)
{
if(TIMx==TIM1)
{
RCC->APB2ENR|=1<<11;
RCC->APB2RSTR|=1<<11;
RCC->APB2RSTR&=~(1<<11);
#ifdef TIME1_UP_IRQ
TIMx->DIER|=1<<0;//配置更新中断
STM32_NVIC_SetPriority(TIM1_UP_IRQn,1,0); //设置中断优先级
printf("TIM1_Init OK!\n");
#endif
}
else if(TIMx==TIM2)
{
RCC->APB1ENR|=1<<0;
RCC->APB1RSTR|=1<<0;
RCC->APB1RSTR&=~(1<<0);
#ifdef TIME2_UP_IRQ
TIMx->DIER|=1<<0;//配置更新中断
STM32_NVIC_SetPriority(TIM2_IRQn,1,0); //设置中断优先级
printf("TIM2_Init OK!\n");
#endif
}
else if(TIMx==TIM3)
{
RCC->APB1ENR|=1<<1;
RCC->APB1RSTR|=1<<1;
RCC->APB1RSTR&=~(1<<1);
#ifdef TIME3_UP_IRQ
TIMx->DIER|=1<<0;//配置更新中断
STM32_NVIC_SetPriority(TIM3_IRQn,1,0); //设置中断优先级
printf("TIM3_Init OK!\n");
#endif
}
else if(TIMx==TIM4)
{
RCC->APB1ENR|=1<<2;
RCC->APB1RSTR|=1<<2;
RCC->APB1RSTR&=~(1<<2);
#ifdef TIME4_UP_IRQ
TIMx->DIER|=1<<0;//配置更新中断
STM32_NVIC_SetPriority(TIM4_IRQn,1,0); //设置中断优先级
printf("TIM4_Init OK!\n");
#endif
}
else
{
printf("TIMx_Init ERROR!\n");
return;
}
/*配置定时器核心寄存器*/
TIMx->PSC=psc-1; //预分频器
TIMx->ARR=arr; //重装载寄存器
TIMx->CR1|=1<<7; //开启缓存功能
//TIMx->CR1|=1<<0; //开启定时器
TIMx->CR1&=~(1<<0); //关闭定时器
}