04 软硬件IIC获取AHT20温湿度传感器数据及扩展测试界面
前言
为了多层次的测评该开发板,通过SPI驱动TFT以便将不同测评环节记录并通过液晶屏显示,到目前为止已体验时钟配置、IO口操作、SPI接口等部分。
目标
设计开发板测试界面;
完成IIC获取AHT20温湿度传感器数据,并在对应测试界面显示。
实现
1、测试界面设计
在完成TFT初始化后基本会是一个单色的界面显示,最好是黑色,这个时候点亮背光后不会出现异常闪烁的现象。
根据流程这个时候应该是一个欢迎界面;
通过操作(欢迎界面中长按或者短按按键)进入菜单界面,这里是各测试模块的选择,通过短按进行各菜单切换,长按进入各子菜单;
子菜单1把LED模式操作放在第一位,通过短按进行LED模式切换,长按返回菜单界面;
子菜单2设计成温湿度大气压力显示界面,也是本章节要进行驱动设计的主要显示界面;
子菜单3待定;
等等;
在LED操作章节已经实现了按键状态的采集(长按或者短按),实现界面操作本质就是按键状态在不同界面下的识别操作,以及各界面下的静态动态显示。
具体效果如下:
2、模拟IIC获取AHT20
硬件IIC之前先通过软件IIC来验证连接及传感器的状态,IIC其实就是两个引脚的IO状态来模拟时序,通过IO口的高低电平及上升下降沿来完美模拟时序。
官方提供的启动代码不用动,直接配置IO口就可以了,本开发板对应的IIC接口是PB7和PB6,注意PB7同时是红灯的控制引脚。
IO口配置配置代码:
#define IIC1_RCU_GPIOB_clock crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE)
#define IIC1_SDA_INITOut IIC1_SDA_GPIO_OutConfig()
#define IIC1_SDA_INITIn IIC1_SDA_GPIO_InConfig()
#define IIC1_SDA_SET gpio_bits_set(GPIOB,GPIO_PINS_7)
#define IIC1_SDA_RESET gpio_bits_reset(GPIOB,GPIO_PINS_7)
#define IIC1_ReadSDA gpio_input_data_bit_read(GPIOB, GPIO_PINS_7)
#define IIC1_SCL_INITOut IIC1_SCL_GPIO_OutConfig()
#define IIC1_SCL_SET gpio_bits_set(GPIOB,GPIO_PINS_6)
#define IIC1_SCL_RESET gpio_bits_reset(GPIOB,GPIO_PINS_6)
void IIC1_SDA_GPIO_OutConfig(void)
{
gpio_init_type gpio_init_struct;
IIC1_RCU_GPIOB_clock;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MAXIMUM;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(GPIOB, &gpio_init_struct);
}
void IIC1_SDA_GPIO_InConfig(void)
{
gpio_init_type gpio_init_struct;
IIC1_RCU_GPIOB_clock;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
void IIC1_IOInit(void)
{
gpio_init_type gpio_init_struct;
IIC1_RCU_GPIOB_clock;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MAXIMUM;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_6|GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(GPIOB, &gpio_init_struct);
IIC1_SDA_SET;
IIC1_SCL_SET;
}
模拟IIC时序代码:
//******************************************************************************
//* 函数名称 : IIC1_IIC_Start()
//* 函数描述 : I2C1开始信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Start(void)
{
IIC1_SDA_SET;
delay_us(8);
IIC1_SCL_SET;
delay_us(14);
IIC1_SDA_RESET;
delay_us(14);
IIC1_SCL_RESET;
delay_us(14);
}
//******************************************************************************
//* 函数名称 : IIC1_IIC_Stop(void)
//* 函数描述 : IIC停止信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_IIC_Stop(void)
{
IIC1_SDA_RESET;
delay_us(14);
IIC1_SCL_SET;
delay_us(8);
IIC1_SDA_SET;
delay_us(14);
}
//******************************************************************************
//* 函数名称 : IIC1_SendACK(uint8_t ack)
//* 函数描述 : 发送应答信号
//* 输入参数 :ack (0:ACK 1:NAK)
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SendACK(uint8_t ack)
{
IIC1_SDA_INITOut;
if(ack == 0)
IIC1_SDA_RESET; //写应答信号
else
IIC1_SDA_SET;
delay_us(14);
IIC1_SCL_SET; //拉高时钟线
delay_us(14); //延时
IIC1_SCL_RESET; //拉低时钟线
delay_us(14); //延时
}
//******************************************************************************
//* 函数名称 : uint8_t IIC1_RecvACK(void)
//* 函数描述 : 接收应答信号
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : RecvACK
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_RecvACK(void)
{
uint8_t RecvACK;
IIC1_SDA_INITIn; //SDA接口为输入
delay_us(8);
IIC1_SCL_SET; //拉高时钟线
delay_us(8); //延时
RecvACK = IIC1_ReadSDA; //读应答信号
IIC1_SCL_RESET; //拉低时钟线
delay_us(8); //延时
IIC1_SDA_INITOut;
return RecvACK;
}
//******************************************************************************
//* 函数名称 : void IIC1_SendByte(uint8_t dat)
//* 函数描述 : 向设备发送一个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_SendByte(uint8_t dat)
{
uint8_t datsendbit;
uint8_t RecvACK;
for (uint8_t i=0; i<8; i++) //8位计数器
{
datsendbit = ((dat & 0x80) >> 7);
dat <<= 1; //移出数据的最高位
if(datsendbit == 1)
{
IIC1_SDA_SET;
}
if(datsendbit == 0)
{
IIC1_SDA_RESET;
} //送数据口
delay_us(8);
IIC1_SCL_SET; //拉高时钟线
delay_us(8); //延时
IIC1_SCL_RESET; //拉低时钟线
delay_us(8);
}
RecvACK = IIC1_RecvACK();
return RecvACK;
}
//******************************************************************************
//* 函数名称 : IIC1_RecvByte()
//* 函数描述 : IIC1接收一个数据
//* 输入参数 :dat
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
uint8_t IIC1_RecvByte(void)
{
uint8_t RecvDat = 0;
IIC1_SDA_INITIn;
for (uint8_t i=0; i<8; i++) //8位计数器
{
RecvDat <<= 1;
IIC1_SCL_SET; //拉高时钟线
delay_us(10); //延时
RecvDat |= (IIC1_ReadSDA);
IIC1_SCL_RESET; //拉低时钟线
delay_us(10); //延时
}
IIC1_SDA_INITOut;
return RecvDat;
}
//******************************************************************************
//* 函数名称 : void IIC1_SendByte(uint8_t dat)
//* 函数描述 : IIC1向设备发送多个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
uint8_t ack = 0;
IIC1_IIC_Start();
IIC1_SendByte(dev_addr<<1);
for(uint8_t i = 0; i < len; i++)
{
ack = IIC1_SendByte(*(dat+i));
}
IIC1_IIC_Stop();
}
//******************************************************************************
//* 函数名称 : IIC1_SendBytes
//* 函数描述 : IIC1从设备接收多个数据
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{
IIC1_IIC_Start();
IIC1_SendByte((dev_addr<<1)+1);
for(uint8_t i = 0; i < len; i++)
{
*(dat+i) = IIC1_RecvByte();
if(i == (len - 1))
{
IIC1_SendACK(1);
}
else
{
IIC1_SendACK(0);
}
}
IIC1_IIC_Stop();
}
3、硬件IIC获取AHT20
参考开发板IICdemo例程进行初始化配置,雅特力的IIC例程中有完整的时序判断定位,非常有助于直接定位失败位置,查找原因。雅特力的官网有一个IIC的配置工具,不过不包含本次开发板的芯片,挺遗憾的。直接引用官方的i2c_application.c,不过遗憾的是并没有调通,单独移植过来也是一样,一直是发送地址错误,大神可以帮忙指导一下,有可能也是传感器的问题,在进行驱动编写是如果IIC发送地址后发送寄存器需要重新开始,才能接受数据,不过这个传感器不用发送寄存器地址直接接受,尝试了还就也没有实现。
实际效果:
其它的没怎么看明白,但是这显示屏那是真的好!
引用: lugl4313820 发表于 2022-8-20 20:28 其它的没怎么看明白,但是这显示屏那是真的好!
其实就是设计了前两个模块的内容,一个是LED测试,一个是温湿度显示
引用: lugl4313820 发表于 2022-8-20 20:28 其它的没怎么看明白,但是这显示屏那是真的好!
屏其实算是比较细腻的,1.54寸的屏分辨率是240*240的