通过上一篇文章我们已经对HPTA 32X32d热堆阵列传感器有了一个比较深入的认识了,接下来我们就可以开始撸码了。
本次使用的也是STM32F103的demo板,如下图所示,外设必须有一个IIC接口,另外利用现成的USB口作为调试口,工程创建就不再赘述了,MDK工程代码还是使用STM32CubeMX 生成。USB虚拟串口驱动代码之前的文章也写过了,这里也不再重复。
1、 IIC驱动代码
看了uutotoyang的文章说使用硬件IIC接口访问HTPA 32X32d有问题,我好奇试了一下,果然有问题,访问EEPROM是正常的,向Sensor发送写控制命令也没问题,主要是向Sensor发送读状态命令失败了,后来还是改为IO模拟IIC,驱动代码如下:
#include "bsp_i2c.h"
#include "main.h"
#define SCL_Pin GPIO_PIN_8
#define SDA_Pin GPIO_PIN_9
#define SDA_GPIO_Port GPIOB
#define SCL_GPIO_Port GPIOB
void bsp_SDA_IN(void) //配置成输入
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
void bsp_SDA_OUT(void)//配置成输出
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
void bsp_SCK_OUT(void) //配置成输出
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
}
#define bsp_IIC_SCL(x) do {(x==0) ? (SCL_GPIO_Port->BRR=SCL_Pin) : (SCL_GPIO_Port->BSRR=SCL_Pin);}while(0);
#define bsp_IIC_SDA(x) do {(x==0) ? (SDA_GPIO_Port->BRR=SDA_Pin) : (SDA_GPIO_Port->BSRR=SDA_Pin);}while(0);
#define bsp_READ_SDA() (SDA_GPIO_Port->IDR & SDA_Pin)
/******************************************************************************
*函 数:void bsp_IIC_Delay(void)
*功 能:IIC延时
*参 数:无
*返回值:无
*备 注: 移植时只需要将bsp_IIC_Delay()换成自己的延时即可
*******************************************************************************/
void bsp_IIC_Delay(uint8_t us)
{
for(int i = 0; i < 16; i++)
{
__asm("NOP");//core bus 160M 情况下大概IIC速率 400K
}
}
/******************************************************************************
*函 数:void IIC_Init(void)
*功 能:IIC初始化
*参 数:无
*返回值:无
*备 注:无
*******************************************************************************/
//#include "string.h"
void bsp_IIC_Init(void)
{
bsp_SCK_OUT();
bsp_SDA_OUT();
bsp_IIC_SCL(1);
bsp_IIC_SDA(1);
}
void bsp_IIC_Start(void)
{
bsp_IIC_SCL(0);
bsp_SDA_OUT(); //sda线输出
bsp_IIC_SDA(1);
bsp_IIC_Delay(4);
bsp_IIC_SCL(1);
bsp_IIC_Delay(4);
bsp_IIC_SDA(0); //START:when CLK is high,DATA change form high to low
bsp_IIC_Delay(4);
bsp_IIC_SCL(0); //钳住I2C总线,准备发送或接收数据
}
void bsp_IIC_Stop(void)
{
bsp_SDA_OUT(); //sda线输出
bsp_IIC_SCL(0);
bsp_IIC_SDA(0); //STOP:when CLK is high DATA change form low to high
bsp_IIC_Delay(4);
bsp_IIC_SCL(1);
bsp_IIC_Delay(4);
bsp_IIC_SDA(1); //发送I2C总线结束信号
bsp_IIC_Delay(4);
}
uint8_t bsp_IIC_WaitAck(void)
{
uint8_t ucErrTime=0;
bsp_SDA_IN(); //SDA设置为输入 (从机给一个低电平做为应答)
bsp_IIC_SDA(1);bsp_IIC_Delay(1);
bsp_IIC_SCL(1);bsp_IIC_Delay(1);;
while(bsp_READ_SDA())
{
ucErrTime++;
if(ucErrTime>250)
{
bsp_IIC_Stop();
return 1;
}
}
bsp_IIC_SCL(0); //时钟输出0
return 0;
}
void bsp_IIC_Ack(void)
{
bsp_IIC_SCL(0);
bsp_SDA_OUT();
bsp_IIC_SDA(0);
bsp_IIC_Delay(1);
bsp_IIC_SCL(1);
bsp_IIC_Delay(2);
bsp_IIC_SCL(0);
}
void bsp_IIC_NAck(void)
{
bsp_IIC_SCL(0);
bsp_SDA_OUT();
bsp_IIC_SDA(1);
bsp_IIC_Delay(1);
bsp_IIC_SCL(1);
bsp_IIC_Delay(1);
bsp_IIC_SCL(0);
}
void bsp_IIC_SendByte(uint8_t data)
{
uint8_t t;
bsp_SDA_OUT();
bsp_IIC_SCL(0); //拉低时钟开始数据传输
for(t=0;t<8;t++)
{
bsp_IIC_SDA((data&0x80)>>7);
bsp_IIC_Delay(1);
bsp_IIC_SCL(1);
data<<=1;
bsp_IIC_Delay(1);
bsp_IIC_SCL(0);
__asm("NOP");
__asm("NOP");
}
bsp_IIC_Delay(1);
}
uint8_t bsp_IIC_ReadByte(uint8_t ack)
{
uint8_t i,receive=0;
bsp_SDA_IN(); //SDA设置为输入模式 等待接收从机返回数据
for(i=0;i<8;i++ )
{
bsp_IIC_SCL(0);
bsp_IIC_Delay(1);
bsp_IIC_SCL(1);
__asm("NOP");
__asm("NOP");
receive<<=1;
if(bsp_READ_SDA())receive++; //从机发送的电平
bsp_IIC_Delay(1);
}
if(ack)
bsp_IIC_Ack(); //发送ACK
else
bsp_IIC_NAck(); //发送nACK
return receive;
}
uint8_t bsp_IIC_ReadByteFromSensor(uint8_t I2C_Addr,uint8_t reg,uint8_t *buf)
{
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck()) //如果从机未应答则数据发送失败
{
bsp_IIC_Stop();
return 1;
}
bsp_IIC_SendByte(reg); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr+1); //进入接收模式
bsp_IIC_WaitAck();
*buf=bsp_IIC_ReadByte(0);
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t bsp_IIC_SendByteToSensor(uint8_t I2C_Addr,uint8_t reg,uint8_t data)
{
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //从机地址写入失败
}
bsp_IIC_SendByte(reg); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte(data);
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //数据写入失败
}
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t bsp_IIC_ReadByteFromEEPROM(uint8_t I2C_Addr,uint16_t reg,uint8_t *buf)
{
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck()) //如果从机未应答则数据发送失败
{
bsp_IIC_Stop();
return 1;
}
bsp_IIC_SendByte((uint8_t)(reg>>8)); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte((uint8_t)reg); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr+1); //进入接收模式
bsp_IIC_WaitAck();
*buf=bsp_IIC_ReadByte(0);
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t bsp_IIC_ReadBytesFromEEPROM(uint8_t I2C_Addr, uint16_t reg, uint8_t *buf, uint16_t len)
{
uint16_t i = 0;
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck()) //如果从机未应答则数据发送失败
{
bsp_IIC_Stop();
return 1;
}
bsp_IIC_SendByte((uint8_t)(reg>>8)); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte((uint8_t)reg); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr+1); //进入接收模式
bsp_IIC_WaitAck();
for(i=0; i<len-1; i++)
{
buf[i] = bsp_IIC_ReadByte(1);
}
buf[i] = bsp_IIC_ReadByte(0);
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t bsp_IIC_SendByteToEEPROM(uint8_t I2C_Addr,uint16_t reg,uint8_t data)
{
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //从机地址写入失败
}
bsp_IIC_SendByte((uint8_t)(reg>>8)); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte((uint8_t)reg); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte(data);
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //数据写入失败
}
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
uint8_t bsp_IIC_SendBytesToEEPROM(uint8_t I2C_Addr,uint16_t reg, uint8_t *data, uint16_t len)
{
uint16_t i = 0;
bsp_IIC_Start();
bsp_IIC_SendByte(I2C_Addr); //发送从机地址
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //从机地址写入失败
}
bsp_IIC_SendByte((uint8_t)(reg>>8)); //发送寄存器地址
bsp_IIC_WaitAck();
bsp_IIC_SendByte((uint8_t)reg); //发送寄存器地址
bsp_IIC_WaitAck();
for(i=0; i<len-1; i++)
{
bsp_IIC_SendByte(data[i]);
}
bsp_IIC_SendByte(data[i]);
if(bsp_IIC_WaitAck())
{
bsp_IIC_Stop();
return 1; //数据写入失败
}
bsp_IIC_Stop(); //产生一个停止条件
return 0;
}
2、读EEPROM
IIC驱动写好以后我们就可以读EEPROM中的参数了,先不要管这些参数怎么用,我们只要把数据读出来,并根据数据手册中规定的EEPROM的数据类型去定义一个结构体类型,再用这个新类型去定义一个变量把EEPROM的数据保存下来备用即可,变量类型和访问EEPROM的相关函数代码如下:
#include "bsp_i2c.h"
#include <stdint.h>
#include <stdio.h>
#define SLAVE_ADDR (0x50<<1)
SENSOR_PARAM_TYPE g_tEEParam = {0};
#define EEPROM_ADDR_PixCmin 0x0000 // float
#define EEPROM_ADDR_PixCmax 0x0004 // float
#define EEPROM_ADDR_GradScale 0x0008 // u8
#define EEPROM_ADDR_TN 0x000B // u16
#define EEPROM_ADDR_Epsilon 0x000D // u8
#define EEPROM_ADDR_MBIT_CALIB 0x001A // u8
#define EEPROM_ADDR_BIAS_CALIB 0x001B // u8
#define EEPROM_ADDR_CLK_CALIB 0x001C // u8
#define EEPROM_ADDR_BPA_CALIB 0x001D // u8
#de