目录
前期准备
移植准备
开始移植
ATH10.c
ATH10.h
main.c
效果图
总结
前期准备
开发硬件:GD32F303RCT6开发板
开发平台:Keil5
网盘资料:见文章底部
移植准备
ATH10模块I2C驱动使用到us延时,因此需要调整时钟频率,调整方法详细请看GD32F303移植4针0.96寸OLED显示屏(I2C)中时钟频率调整部分,这里就不过多讲解了。
开始移植
ATH10.c
#include "gd32f30x.h"
#include "systick.h"
#include <stdio.h>
#include "ath10.h"
/*
初始化ATH10 GPIO引脚
*/
void ath10_iic_gpio_init(void)
{
// 使能GPIOB时钟
rcu_periph_clock_enable(ATH10_ENABLE_GPIO);
// 配置ATH10_SDA_PIN为输出
gpio_init(ATH10_SDA_GPIO, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, ATH10_SDA_PIN);
// 配置ATH10_SCL_PIN为输出
gpio_init(ATH10_SCL_GPIO, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, ATH10_SCL_PIN);
ATH10_SDA_H;
ATH10_SCL_H;
}
/*
SDA模式切换
mode: 1:输出
0:输入
*/
void ath10_iic_sda_mode(uint8_t mode)
{
// 使能GPIOB时钟
rcu_periph_clock_enable(ATH10_ENABLE_GPIO);
if (mode)
{
// 配置ATH10_SDA_PIN为输出
gpio_init(ATH10_SDA_GPIO, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,ATH10_SDA_PIN);
}
else
{
// 配置ATH10_SDA_PIN为上拉输入
gpio_init(ATH10_SDA_GPIO, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,ATH10_SDA_PIN);
}
}
/*
读取SDA 输入模式下的引脚状态
*/
uint8_t read_sda_in_mode_data(void)
{
return gpio_input_bit_get(ATH10_SDA_GPIO, ATH10_SDA_PIN);
}
/*
主机发送开始信号
*/
void ath10_start(void)
{
ATH10_SDA_OUT; // SDA为输出模式
ATH10_SCL_H; // 拉高SCL
ATH10_SDA_H; // 拉高SDA
delay_us(5);
ATH10_SDA_L; // 先拉低SDA,持续5us
delay_us(5);
ATH10_SCL_L; // 再拉低SCL
}
/*
主机发送停止信号
*/
void ath10_stop(void)
{
ATH10_SDA_OUT; // SDA为输出模式
ATH10_SCL_L; // 拉低SCL
ATH10_SDA_L; // 拉低SDA
delay_us(5);
ATH10_SCL_H; // 先拉高SCL,持续5us
delay_us(5);
ATH10_SDA_H; // 再拉高SDA
}
/*
等待从机应答
返回: 0:收到应答
1:未收到应答
*/
uint8_t ath10_wait_ack(void)
{
uint8_t ErrTime = 0;
ATH10_SDA_IN;
ATH10_SDA_H;
delay_us(1);
ATH10_SCL_H;
delay_us(1);
// 循环读取SDA引脚状态
while (read_sda_in_mode_data())
{
ErrTime++;
if (ErrTime > 250)
{
ath10_stop();
return 1;
}
}
ATH10_SCL_L;
delay_us(1);
return 0;
}
/*
主机是否发送应答
ack: 1:发送
0:不发送
*/
void ath10_send_ack(uint8_t ack)
{
ATH10_SCL_L;
ATH10_SDA_OUT;
if (ack) ATH10_SDA_L;
else ATH10_SDA_H;
delay_us(2);
ATH10_SCL_H;
delay_us(2);
ATH10_SCL_L;
}
/*
主机发送一个字节
*/
void ath10_send_Byte(uint8_t data)
{
uint8_t i;
ATH10_SDA_OUT;
ATH10_SCL_L;
delay_us(2);
for (i=0; i<8; i++)
{
if ((data<<i) & 0x80) ATH10_SDA_H;
else ATH10_SDA_L;
ATH10_SCL_H;
delay_us(2);
ATH10_SCL_L;
delay_us(2);
}
}
/*
主机读取一个字节
*/
uint8_t ath10_read_Byte(void)
{
uint8_t i, receive = 0;
ATH10_SCL_L;
ATH10_SDA_IN;
delay_us(2);
for (i=0; i<8; i++)
{
ATH10_SCL_H;
delay_us(1);
receive<<=1;
if (read_sda_in_mode_data()) receive ++;
ATH10_SCL_L;
delay_us(1);
}
return receive;
}
/*
检测ATH10是否响应
返回: 1:未响应
0:响应
*/
uint8_t ath10_check(void)
{
uint8_t ack = 0;
ath10_start();
ath10_send_Byte(ATH10_ADDRESS);
ack = ath10_wait_ack();
ath10_stop();
return ack;
}
/*
初始化ATH10
*/
uint8_t ath10_init(void)
{
ath10_iic_gpio_init();
ath10_start();
ath10_send_Byte(ATH10_ADDRESS);
ath10_wait_ack();
ath10_send_Byte(0xe1);
ath10_wait_ack();
ath10_send_Byte(0x08);
ath10_wait_ack();
ath10_send_Byte(0x00);
ath10_wait_ack();
ath10_stop();
delay_1ms(40); // 延时40ms,使传感器稳定
return 1;
}
/*
ATH10 软件复位
*/
void ath10_reset(void)
{
ath10_start();
ath10_send_Byte(ATH10_WRITE);
ath10_wait_ack();
ath10_send_Byte(0xba);
ath10_wait_ack();
ath10_stop();
}
/*
读取ATH10 温湿度数据
返回: 0:获取成功
1:获取失败
*/
uint8_t ath10_read_data(uint16_t *temp, uint16_t *humi)
{
// 状态(第1数据)
uint8_t state = 0;
// 数据2-6
uint8_t databuf[5];
// for循环次数
uint8_t i;
// 温度、湿度缓冲区
uint32_t temp_buf = 0, humi_buf = 0;
/*----------------- 触发测量 -----------------------*/
ath10_start();
ath10_send_Byte(ATH10_WRITE);
ath10_wait_ack();
ath10_send_Byte(0xac);
ath10_wait_ack();
ath10_send_Byte(0x33);
ath10_wait_ack();
ath10_send_Byte(0x00);
ath10_wait_ack();
ath10_stop();
delay_1ms(80); // 手册中要求主机发出测量指令(0xAC)后,需延时75ms以上
/*---------------------------------------------------*/
ath10_start();
ath10_send_Byte(ATH10_READ);
ath10_wait_ack();
state = ath10_read_Byte();
ath10_send_ack(1);
// 首次读取为状态数据,判断Bit7位,0表示可正常读取,1表示传感器正忙
if ((state&0x80) == 0)
{
for (i=0; i<5; i++)
{
databuf[i] = ath10_read_Byte();
if (i == 4) ath10_send_ack(0);
else ath10_send_ack(1);
}
ath10_stop();
// 第2、3数据,第4数据高4位为湿度数据
humi_buf = (databuf[0]<<12) + (databuf[1]<<4) + (databuf[2]>>4);
// 第4数据低4位,第5、6数据为湿度数据
temp_buf = ((databuf[2]&0x0f)<<16) + (databuf[3]<<8) + (databuf[4]);
*humi = humi_buf*1000/1024/1024;
*temp = temp_buf*2000/1024/1024-500;
printf("获取温湿度成功!\r\n");
return 0;
}
printf("获取温湿度失败!\r\n");
ath10_stop();
return 1;
}
ATH10.h
#ifndef ATH10_H
#define ATH10_H
/*-------------------------------- GPIO ------------------------------------------*/
#define ATH10_ENABLE_GPIO RCU_GPIOB
#define ATH10_SDA_GPIO GPIOB
#define ATH10_SCL_GPIO GPIOB
#define ATH10_SDA_PIN GPIO_PIN_1
#define ATH10_SCL_PIN GPIO_PIN_2
#define ATH10_SDA_H gpio_bit_write(ATH10_SDA_GPIO, ATH10_SDA_PIN, SET)
#define ATH10_SDA_L gpio_bit_write(ATH10_SDA_GPIO, ATH10_SDA_PIN, RESET)
#define ATH10_SCL_H gpio_bit_write(ATH10_SCL_GPIO, ATH10_SCL_PIN, SET)
#define ATH10_SCL_L gpio_bit_write(ATH10_SCL_GPIO, ATH10_SCL_PIN, RESET)
#define OUT_MODE 1
#define IN_MODE 0
#define ATH10_SDA_OUT ath10_iic_sda_mode(OUT_MODE)
#define ATH10_SDA_IN ath10_iic_sda_mode(IN_MODE)
/*-------------------------------- ADDRESS ------------------------------------------*/
#define ATH10_ADDRESS 0x70
#define ATH10_WRITE 0x70
#define ATH10_READ 0x71
/*-------------------------------- Func Dec ------------------------------------------*/
void ath10_iic_gpio_init(void);
void ath10_iic_sda_mode(uint8_t mode);
uint8_t read_sda_in_mode_data(void);
void ath10_start(void);
void ath10_stop(void);
uint8_t ath10_wait_ack(void);
void ath10_send_ack(uint8_t ack);
void ath10_send_Byte(uint8_t data);
uint8_t ath10_read_Byte(void);
uint8_t ath10_check(void);
uint8_t ath10_init(void);
void ath10_reset(void);
uint8_t ath10_read_data(uint16_t *temp, uint16_t *humi);
/*-------------------------------- End ------------------------------------------*/
#endif
main.c
#include "gd32f30x.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "ath10.h"
uint16_t temp = 0;
uint16_t humi = 0;
char temp_string[32];
char humi_string[32];
int main(void)
{
uint8_t flag = 0;
// 设置主频120MHZ -- 分频器选择
rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);
// 配置系统时钟 -- 1us
systick_config();
// 使能AF时钟 -- 开启GPIO复用功能
rcu_periph_clock_enable(RCU_AF);
// 延时1s
delay_1ms(1000);
// 将SWJ和NRST引脚重新映射到其他可用的引脚上,以确保它们不会与其他外设引脚功能发生冲突。
// 即可当作普通IO引脚使用
gpio_pin_remap_config(GPIO_SWJ_NONJTRST_REMAP, ENABLE);
flag = ath10_init();
if (flag == 0)
{
printf("Init Error!\r\n");
return 0;
}
while (1)
{
if ( ath10_read_data(&temp, &humi) == 0)
{
sprintf(temp_string,"Temp:%d%d.%d C", temp/100, (temp/10)%10, temp%10);
sprintf(humi_string,"Humi:%d%d.%d RH", humi/100, (humi/10)%10, humi%10);
printf("%s -- %s\r\n", temp_string, humi_string);
}
delay_1ms(100);
}
}
串口打印部分的代码根据自身的情况进行添加,这里作者就不加上了。
效果图
总结
写的比较简洁,如有遗漏之处还请各位大佬指正,我是陈师傅,我们下章再见!
ATH10https://pan.baidu.com/s/12tqMsbFS1bO-oHjrjvC4kQ?pwd=3p8b