Си библиотека для работы с 1-Wire устройствами
31/12/2010 - 16:03
Pavel Bobkov
Для работы с устройствами, поддерживающими 1-Wire протокол уже давным-давно написаны библиотеки. Поэтому нет смысла изобретать велосипед (лично я это уже делал, когда программировал на ассемблере) и писать что-то свое. На сайте фирмы ATMEL есть замечательный application note AVR318: Dallas 1-Wire, в котором рассмотрены два варианта реализации 1-Wire протокола на микроконтроллерах AVR – программная и аппаратная. Программная реализация позволяет использовать однопроводный протокол на любых микроконтроллерах. Аппаратная – только на тех, на которых есть модуль UART. Аппаратной поддержки 1-Wire протокола «в чистом виде» микроконтроллеры AVR не имеют, однако, используя модуль UART неким хитрым образом, эту поддержку можно организовать. К application note идет проект. Я взял из этого проекта исходные файлы библиотеки, добавил, изменил несколько функций и написал файл compilers.h, чтобы можно было использовать эту либу с любым из трех компиляторов – IAR AVR, GNU GCC (WINAVR), CodeVision.
Библиотека состоит из следующих файлов
Библиотека состоит из следующих файлов
OWISWBitFunction.h
OWISWBitFunction.c
OWIUARTBitFunction.c
OWIHighLevelFunction.h
OWIHighLevelFunction.c
OWIPolled.h
compilers.h
OWIdefs.h
OWIdevicespecific.h
OWIcrc.h
OWIcrc.c
Как подключить библиотеку к проекту
Процесс интеграции 1-Wire библиотеки с проектом заключается в следующем:
- переписываем файлы библиотеки в папку проекта
- подключаем сишные файлы к проекту
OWIHighFunction.c
OWISWBitFunction.c
OWIUARTBitFunction.c
OWIcrc.c
- добавляем заголовочные файлы в main.c
#include "OWIPolled.h"
#include "OWIHighLevelFunctions.h"
#include "OWIBitFunctions.h"
#include "common_files\OWIcrc.h"
- настраиваем файл OWIPolled.h
- выбираем реализацию OneWire интерфейса – программную
#define OWI_SOFTWARE_DRIVER
//#define OWI_UART_DRIVER
- задаем тактовую частоту микроконтроллера
#define CPU_FREQUENCY 16.000
- задаем порт, к которому подключена OneWire шина
#define OWI_PORT PORTD //!< 1-Wire PORT Data register.
#define OWI_PIN PIND //!< 1-Wire Input pin register.
#define OWI_DDR DDRD //!< 1-Wire Data direction register.
- в main.c задаем вывод, к которому подключена OneWire шина
#define BUS OWI_PIN_7
Для GCC проектов в makefile нужно будет добавить все сишные файлы.
Например, так:
SRC = $(TARGET).c bcd.c lcd_lib.c OWISWBitFunctions.c OWIHighLevelFunctions.c OWIUARTBitFunctions.c common_files/OWIcrc.c
Файлы
Application note AVR318: Dallas 1-Wire
Проекты проверялись в железе и никаких нареканий не вызывали. В Proteus`е я их тоже запустил, но не сразу. Оказывается по умолчанию датчикам DS18B20 присваиваются одинаковые адреса. При использовании нескольких датчиков адреса нужно подправить ручками.
Подробное описание проектов будет уже в новом году...
Проекты проверялись в железе и никаких нареканий не вызывали. В Proteus`е я их тоже запустил, но не сразу. Оказывается по умолчанию датчикам DS18B20 присваиваются одинаковые адреса. При использовании нескольких датчиков адреса нужно подправить ручками.
Подробное описание проектов будет уже в новом году...
Tagged under
Comments
Тактовая процессора 8MHZ ,и адрес одного датчика поменять. (Proeus по умолчанию лепит одинаковые для всех)
Спасибо!
Предпочтительней уменьшить время в настройках модели датчика процентов на 30. (проверял - помогает с IAR 5.3 и Proteus 7.7 Sp2; макет на ATMEGA8515 4MHz)
а 18S20 или 1820 (без буквы)
Чтобы использовать проект "работа с одним датчиком DS18B20" для датчика DS18S20, нужно изменить кусок вывода значения температуры на дисплей
Code:
/*выводим знак*/
LCD_Goto(5,0);
if ((scratchpad[1]&128) == 0){
LCD_WriteData('+');
}
else{
LCD_WriteData('-');
tmp = ((unsigned int)scratchpad[1]<<8)|scratchpad[0];
tmp = ~tmp + 1;
scratchpad[0] = tmp;
scratchpad[1] = tmp>>8;
}
/*выводим целую часть*/
temperature = (scratchpad[0]>>4)|((scratchpad[1]&7)<<4);
BCD_3Lcd(temperature);
/*выводим дробную часть*/
temperature = (scratchpad[0]&15);
temperature = (temperature>>1) + (temperature>>3);
LCD_WriteData('.');
BCD_1Lcd(temperature);
на
Code:
LCD_Goto(5,0);
if ((scratchpad[1]&128) == 0){
LCD_WriteData('+');
}
else{
LCD_WriteData('-');
}
temperature = (scratchpad[0]>>1);
BCD_3Lcd(temperature);
Code:
/*выводим знак*/
LCD_Goto(5,0);
if ((scratchpad[1]&128) == 0){
LCD_WriteData('+');
}
else{
LCD_WriteData('-');
tmp = ((unsigned int)scratchpad[1]<<8)|scratchpad[0];
tmp = ~tmp + 1;
scratchpad[0] = tmp;
scratchpad[1] = tmp>>8;
}
/*выводим целую часть*/
temperature = (scratchpad[0]>>4)|((scratchpad[1]&7)<<4);
BCD_3Lcd(temperature);
/*выводим дробную часть*/
temperature = (scratchpad[0]&15);
temperature = (temperature>>1) + (temperature>>3);
LCD_WriteData('.');
BCD_1Lcd(temperature);
на более короткий и лаконичный:
Code:
LCD_Goto(5,0);
if ((scratchpad[1]&128) == 0){
LCD_WriteData('+');
}else{
LCD_WriteData('-');
}
int reading = (scratchpad[1]<<8) + scratchpad[0];
if (reading & 0x8000) {
reading = (reading ^ 0xffff) + 1;
}
float temp = (6 * reading) + reading / 4;
dtostrf((temp/100),2,2,temperature);
LCD_SendString(temperature);
LCD_WriteData('C');
После этого можно избавиться от файла bcd.c в Makefile
Не забыть добавить вначале main.c
#include и убрать #include "bcd.h"
После
int main( void )
{
удалить
unsigned int tmp = 0;
unsigned char temperature;
добавить
Code:
#include<stdlib.h>
int main(void)
{
unsigned char temperature[20];
А так, огромное спасибо за такие полезные статьи!
P.S. Кстате, почему то не приходит письмо с активацией моего акаунта CHERTS :(
Кстати, с чего вы решили, что dtostrf более простая? Видели исходники этой функции. Посмотрите.
www.koders.com/c/fid59843B28432C0FF3F7D5DA5BE2A2F4051E5E095E.aspx?s=dtoa_prf#L54
www.koders.com/c/fidDB4D83581A0529937AFB0C8F77401277E6F372AA.aspx?s=dtoa_prf#L29
Quote: Может быть не правильно указали е-mail, может быть движок глючит.Я активировал ваш аккаунт вручную.
Code:
temperature = (scratchpad[0]&15);
temperature = (temperature>>1) + (temperature>>3);
LCD_WriteData('.');
BCD_1Lcd(temperature);
При обработке возникает погрешность (это можно легко проверить: пусть датчик померил 0,9375 гр. или 0x0F, на LCD выведет - 0,8гр. цельсия)
Правильнее написать так:
Code:
temperature = (scratchpad[0]&15);
temperature = (temperature<<1) + (temperature<<3);// Умножаем на 10
temperature = (temperature>>4);//делим на 16 или умножаем на 0,0625
LCD_WriteData('.');
BCD_1Lcd(temperature);
как запрограммирова ть R0=0, R1=0
Заранее спасибо
1. В Atmel Studio в упор не компилился проект, с ошибкой No such file or directory, на файл compilers.h, пока в свойствах проекта не указал include folders, добавил корневой каталог проекта, и папку common_files.
2. В протеусе в упор не виделись датчики, ни один, ни несколько сразу. Даже на Presence не отвечали. Проблема решилась заменой Code:
#define OWI_DELAY_OFFSET_CYCLES 13 //!< Timing delay when pulling bus low and releasing bus.
на значение 7 или ниже. При значении 8 - уже не работает. В железе пока не проверялось.Code:
/*ждем, когда датчик завершит преобразование*/
while (!OWI_ReadBit(BUS));
наличие датчика проверял функцией OWIsearchRom, датчик находится, если он подключен, не находится, если отключен.
delay_ms(800);
всё так же, протеус - работает, железо - нет
Контролер Atmega8,кварц 16 МГц.Фокус с proteus в плане понижения в два раза частоты в свойствах Atmega8 - работает.Иначе температура на LCD +0,00.
Еще раз спасибо за библиотеку.
AVR GNU C Compiler
1) Если у вас makefile project - прописываеие пути в makefile :)
2) Проект с визуальными настройками - открываете свойства проекта - вкладка Toolchain - AVR GNU C Compiler -Directories. Там вписываете нужные пути.
Там нужно прописать пути:
../common_files
../
Такая ошибка:"undefin ed reference to `OWI_Init'"
Atmel Studio 6.2
В чем может быть проблема?
Code:
extern "C"
{
#include "OWIHighLevelFunctions.h"
#include "OWIBitFunctions.h"
#include "common_files/OWIcrc.h"
}
RSS feed for comments to this post