【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
前面我们讨论的几个模块,比如说蜂鸣器,比如说液晶屏,这些都是输出模块。但是好像没有讨论到输入模块。因为输出模块比较好理解,就是处理完的结果通过一些接口送出来,比如说串口、屏幕、蜂鸣器、led等等,让外界知道当前处理结果是什么样的。那输入呢,输入主要就是感知外部世界,可以是湿度、温度、转速、压力等变量。从这个角度说,前面讨论过的boot按键输入,虽然形式上也是一种输入,但是从实际效用来说,更多的是作为一种人机交互使用的。

1、DS18B20模块
这个模块和蜂鸣器一样,也是三个pin。这种三pin的模块,一般就是电源、地、信号。只不过和蜂鸣器单向输入不同,18B20的signal pin既有输入,也有输出,这是差异的地方。
2、电压
电压部分的话,直接使用3.3v就好了,不像屏幕或者电机,一般都要5v左右。甚至于像有的步进电机,还需要12v的输入。
3、寻找匹配的gpio口
既然温度模块是一个pin,那么与之对应的esp32模块,也找到一个pin就好了。这里不失一般性,我们找到了一个gpio 13的管脚。
4、利用ai工具进行编程
ai编程的关键,主要就是需求描述清楚。比如可以这样说,我们使用的是esp32模块,现在需要读取ds18b20模块,这个模块有3个pin,一个是3.3v,一个gnd,还有一个signal pin对接esp32模块的gpio 13,现在需要编写一段代码,定时打印当前的环境温度数值。通过这样的方式,就可以让ai打印出相应的代码了。
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_rom_sys.h"
// DS18B20 configuration
#define DS18B20_PIN 13 // Data pin connected to GPIO13
#define DS18B20_CONVERT_T 0x44 // Convert temperature command
#define DS18B20_READ_SCRATCH 0xBE // Read scratchpad command
#define DS18B20_SKIP_ROM 0xCC // Skip ROM command
// Set GPIO pin as output
static void ds18b20_set_output(void)
{
gpio_set_direction(DS18B20_PIN, GPIO_MODE_OUTPUT);
}
// Set GPIO pin as input with pull-up
static void ds18b20_set_input(void)
{
gpio_set_direction(DS18B20_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(DS18B20_PIN, GPIO_PULLUP_ONLY);
}
// Write one bit to DS18B20
static void ds18b20_write_bit(uint8_t bit)
{
ds18b20_set_output();
gpio_set_level(DS18B20_PIN, 0);
if (bit)
{
// Write 1: pull low for 1-15us, then release
esp_rom_delay_us(10);
ds18b20_set_input();
esp_rom_delay_us(55);
}
else
{
// Write 0: pull low for 60-120us
esp_rom_delay_us(60);
ds18b20_set_input();
esp_rom_delay_us(5);
}
}
// Write one byte to DS18B20
static void ds18b20_write_byte(uint8_t byte)
{
for (int i = 0; i < 8; i++)
{
ds18b20_write_bit(byte & 0x01);
byte >>= 1;
}
}
// Read one bit from DS18B20
static uint8_t ds18b20_read_bit(void)
{
uint8_t bit = 0;
ds18b20_set_output();
gpio_set_level(DS18B20_PIN, 0);
esp_rom_delay_us(2);
ds18b20_set_input();
esp_rom_delay_us(10);
if (gpio_get_level(DS18B20_PIN))
{
bit = 1;
}
esp_rom_delay_us(50);
return bit;
}
// Read one byte from DS18B20
static uint8_t ds18b20_read_byte(void)
{
uint8_t byte = 0;
for (int i = 0; i < 8; i++)
{
byte |= (ds18b20_read_bit() << i);
}
return byte;
}
// DS18B20 reset and presence detect
static uint8_t ds18b20_reset(void)
{
uint8_t presence = 0;
ds18b20_set_output();
gpio_set_level(DS18B20_PIN, 0);
esp_rom_delay_us(480);
ds18b20_set_input();
esp_rom_delay_us(60);
if (!gpio_get_level(DS18B20_PIN))
{
presence = 1;
}
esp_rom_delay_us(420);
return presence;
}
// Read temperature from DS18B20
float ds18b20_read_temperature(void)
{
uint8_t scratchpad[9] = {0};
int16_t temp_raw = 0;
float temperature = 0.0f;
// Reset and check presence
if (!ds18b20_reset())
{
printf("DS18B20 not found!\n");
return -999.0;
}
// Skip ROM
ds18b20_write_byte(DS18B20_SKIP_ROM);
// Start temperature conversion
ds18b20_write_byte(DS18B20_CONVERT_T);
// Wait for conversion (max 750ms for 12-bit resolution)
vTaskDelay(800 / portTICK_PERIOD_MS);
// Reset again
ds18b20_reset();
// Skip ROM
ds18b20_write_byte(DS18B20_SKIP_ROM);
// Read scratchpad
ds18b20_write_byte(DS18B20_READ_SCRATCH);
// Read 9 bytes from scratchpad
for (int i = 0; i < 9; i++)
{
scratchpad[i] = ds18b20_read_byte();
}
// Calculate temperature
temp_raw = (scratchpad[1] << 8) | scratchpad[0];
temperature = temp_raw / 16.0;
return temperature;
}
// Initialize DS18B20
void ds18b20_init(void)
{
gpio_config_t io_conf =
{
.pin_bit_mask = (1ULL << DS18B20_PIN),
.mode = GPIO_MODE_INPUT_OUTPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
printf("DS18B20 initialized on GPIO%d\n", DS18B20_PIN);
}
void app_main(void)
{
float temperature = 0.0f;
int temp_int = 0;
int temp_dec = 0;
printf("DS18B20 Temperature Sensor Driver\n");
printf("Data pin: GPIO%d\n", DS18B20_PIN);
// Initialize DS18B20
ds18b20_init();
while (1)
{
// Read temperature
temperature = ds18b20_read_temperature();
// Print temperature
if (temperature != -999.0)
{
// Convert float to integer parts to avoid float printf issues
temp_int = (int)temperature;
temp_dec = (int)((temperature - temp_int) * 100);
if (temp_dec < 0) temp_dec = -temp_dec;
printf("Temperature: %d.%02d C\n", temp_int, temp_dec);
}
else
{
printf("Failed to read temperature!\n");
}
// Wait 1 second before next reading
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
5、编译代码和调试代码
实际开发的时候,我们也会发现一些问题。比如有的时候生成的代码,并不能编译通过,这种情况下要么手动改写,要么重新生成。还有的时候,代码需要进行微调处理,比如打印格式不正确等等。这些工作都说明,我们用ai的前提,是需要自己对嵌入式本身有一个基本了解,至少知道问题出在什么地方,这样才方便后面进行改进和优化。
另外,修改代码的时候一定要做好版本管理,很多时候ai生成的代码并不能一下子就能满足要求,它也需要自己不停改进。
实际测试的时候,可以一开始看看有没有数据正常打印出来,如果可以的话,再把手指按上去,看看温度有没有升高,这一切都ok的话,基本上代表温度传感器已经用起来了。如果没有,就要回去检查下原因了,看看是硬件的原因,还是软件的原因。
6、其他的传感器模块和温度模块高度相似
**温度模块,让我们第一次可以通过传感器可以获得真实世界的数据。**并且,其他类似的模块也是差不多这个套路。即,三个pin,一个电源,一个地,还有一个信号线,这根信号线既负责输入,也负责输出。
此时,加上前面的屏幕、蜂鸣器,以及后面会学习的继电器、电机等模块,这就让mcu主控开始有了价值。这个价值,就是让mcu主控可以去构建某一个,或者是某一种类型的自动化设备,通过这个设备可以大大降低人的工作量,从而提高生活的品质。我想,这就是mcu或者soc的价值所在。