Для чтения данных с датчика температуры DS18B20 с использованием только операций записи и чтения битов (0 или 1) в порт, необходимо реализовать протокол 1-Wire "вручную". Это требует точного управления временем и последовательностью операций.
Ниже приведен пример кода на C для чтения температуры с DS18B20, используя только операции записи и чтения битов:
________________________________________
Код на C для чтения температуры с DS18B20
#include <avr/io.h> #include <util/delay.h>
// Пин, к которому подключен DS18B20 #define DS18B20_PIN PB0 #define DS18B20_PORT PORTB #define DS18B20_DDR DDRB #define DS18B20_PIN_REG PINB
// Функция для установки пина в режим вывода void set_pin_output() { DS18B20_DDR |= (1 << DS18B20_PIN); }
// Функция для установки пина в режим ввода void set_pin_input() { DS18B20_DDR &= ~(1 << DS18B20_PIN); }
// Функция для записи бита в DS18B20 void write_bit(uint8_t bit) { set_pin_output(); DS18B20_PORT &= ~(1 << DS18B20_PIN); // Начало слота записи _delay_us(2); // Задержка для низкого уровня if (bit) { DS18B20_PORT |= (1 << DS18B20_PIN); // Если бит = 1, поднимаем уровень } _delay_us(60); // Задержка для завершения слота DS18B20_PORT |= (1 << DS18B20_PIN); // Возвращаем высокий уровень _delay_us(2); // Задержка для восстановления }
// Функция для чтения бита из DS18B20 uint8_t read_bit() { uint8_t bit = 0; set_pin_output(); DS18B20_PORT &= ~(1 << DS18B20_PIN); // Начало слота чтения _delay_us(2); // Задержка для низкого уровня set_pin_input(); // Переключаем пин в режим ввода _delay_us(10); // Задержка для стабилизации if (DS18B20_PIN_REG & (1 << DS18B20_PIN)) { bit = 1; // Если уровень высокий, бит = 1 } _delay_us(50); // Задержка для завершения слота return bit; }
// Функция для отправки команды в DS18B20 void send_command(uint8_t command) { for (uint8_t i = 0; i < 8; i++) { write_bit(command & 0x01); // Отправляем младший бит command >>= 1; // Сдвигаем команду вправо } }
// Функция для чтения байта из DS18B20 uint8_t read_byte() { uint8_t byte = 0; for (uint8_t i = 0; i < 8; i++) { byte >>= 1; // Сдвигаем байт вправо if (read_bit()) { byte |= 0x80; // Устанавливаем старший бит, если прочитали 1 } } return byte; }
// Функция для инициализации DS18B20 uint8_t ds18b20_init() { set_pin_output(); DS18B20_PORT &= ~(1 << DS18B20_PIN); // Начало сигнала сброса _delay_us(480); // Задержка для сигнала сброса set_pin_input(); // Переключаем пин в режим ввода _delay_us(70); // Задержка для ожидания ответа if (!(DS18B20_PIN_REG & (1 << DS18B20_PIN))) { _delay_us(410); // Задержка для завершения сигнала сброса return 1; // Успешная инициализация } return 0; // Ошибка инициализации }
// Функция для чтения температуры float read_temperature() { uint8_t temp_lsb, temp_msb; int16_t temp_raw; if (ds18b20_init()) { send_command(0xCC); // Пропуск ROM (если один датчик на шине) send_command(0x44); // Команда для начала преобразования температуры _delay_ms(750); // Ожидание завершения преобразования ds18b20_init(); send_command(0xCC); // Пропуск ROM send_command(0xBE); // Команда для чтения данных temp_lsb = read_byte(); // Чтение младшего байта температуры temp_msb = read_byte(); // Чтение старшего байта температуры temp_raw = (temp_msb << 8) | temp_lsb; // Объединение байтов return (float)temp_raw / 16.0; // Преобразование в градусы Цельсия } return -999.0; // Ошибка чтения }
int main() { float temperature; while (1) { temperature = read_temperature(); if (temperature != -999.0) { // Вывод температуры (например, на дисплей или в UART) // Здесь можно добавить код для вывода температуры } _delay_ms(1000); // Задержка между измерениями } }
Объяснение кода:
1. Управление пином:
- Функции set_pin_output() и set_pin_input() переключают пин между режимом вывода и ввода.
- Функции write_bit() и read_bit() реализуют протокол 1-Wire для записи и чтения битов.
2. Инициализация DS18B20:
- Функция ds18b20_init() отправляет сигнал сброса и проверяет ответ от датчика.
3. Чтение температуры:
- Функция read_temperature() отправляет команды для начала преобразования температуры и чтения данных.
- Температура возвращается в градусах Цельсия.
4. Основной цикл:
- В бесконечном цикле температура считывается каждую секунду.
________________________________________
Важные моменты:
• Точность временных задержек критична для работы протокола 1-Wire.
• Код написан для микроконтроллера AVR (например, ATmega328P, используемого в Arduino). Для других микроконтроллеров потребуется адаптация.
• Если используется несколько датчиков на одной шине, потребуется реализация поиска устройств (ROM-команды).