Привет. Вот в этом уроке я покажу вам как быстро спаять простой термометр. Для этого нам понадобиться ATMega8, LCD(16*2), DS18B20, печатная плата, панелька для микроконтроллера.
Итак, приступим, сначала откроем Code Vision AVR. Создаем новый проект, без использования мастера, потом создаем текстовый документ с расширением ".с" и добавляем туда следующий код:
#include <mega8.h> //библиотека ввода\вывода #include <delay.h> //библиотека задержки #asm //сообщаем куда подключен датчик .equ __w1_port=0x15; PORTC .equ __w1_bit=3 #endasm #asm //сообщаем куда подключён экран .equ __lcd_port=0x18 #endasm #include <lcd.h> //библиотека для LCD #include <1wire.h> //библиотека работы с 1Wire #include <ds18b20.h> //библиотека для работы с датчиком ds18b20 #include <stdio.h> //ненаю что за библиотека, но без неё неполучается char lcd_buffer[33]; //масив с данными для экрана void main(void) { unsigned char devices; //переменная в которой количество присоеденённых датчиков int temp; //переменная для хранения температуры lcd_init(16); //инициилизация LCD, и говорим что он на 16 символов devices=w1_init(); //ищим датчики while(devices>0) //бесконечный цикл, если датчик подключон { temp=ds18b20_temperature(0); //читаем температуру if (temp>1000){ //если датчик выдаёт больше 1000 temp=4096-temp; //отнимаем от данных 4096 temp=-temp; //и ставим знак "минус" } sprintf(lcd_buffer,"t=%i.%u\xdfC",temp,temp%1); //записуемв масив для экрана температуру и всё такое lcd_clear(); //чистим дисплей перед выводом lcd_puts(lcd_buffer); //выводим масив на LCD delay_ms(500); //ждём 500мс }; }
потом компилируем и выбираем частоту 8 МГц. Прошиваем, и еще прошиваем фюзы на ту же частоту
вот вариант с точностью до 0.1, правда здесь дисплей от Nokia 3310. Датчик подключен на PD2.
/***************************************************** ATmega8 4,000000 MHz *****************************************************/ #include <mega8.h> // 1 Wire Bus functions #asm .equ __w1_port=0x12 ;PORTD .equ __w1_bit=2 #endasm #include <1wire.h> // DS1820 Temperature Sensor functions #include <ds18b20.h> #include <delay.h> // maximum number of DS1820 devices // connected to the 1 Wire bus #define MAX_DS18B20 3 // number of DS1820 devices // connected to the 1 Wire bus unsigned char ds18b20_devices; // DS1820 devices ROM code storage area, // 9 bytes are used for each device // (see the w1_search function description in the help) unsigned char ds18b20_rom_codes[MAX_DS18B20][9]; #include <3310lcd.c> #include <stdio.h>
// Declare your global variables here float temper; int temper_int,temper_fl,min=0;
void temperature(void) // функция по работе с термо-датчиком { temper=ds18b20_temperature(&ds18b20_rom_codes[0][0]); temper_int=temper; // отбор целой части от температуры if(temper<0) // при отрицательной температуре { temper_fl=(temper-temper_int-0.0625)*10; // дробная часть temper_int=-((temper_int*10)+temper_fl); // температура*10 min=1; // минус }else // при положительной { temper_fl=(temper-temper_int)*10; // дробная часть temper_int=(temper_int*10)+temper_fl;// температура*10 min=0; // плюс } } void main(void) { // Determine the number of DS1820 devices // connected to the 1 Wire bus ds18b20_devices=w1_search(0xf0,ds18b20_rom_codes); ds18b20_init(0,-35,35,DS18B20_12BIT_RES); // переключения термометра в 12 битный режим
LcdInit(); // LCD module initialization
while (ds18b20_devices>0 ) { // Place your code here delay_ms(500); temperature(); // вызываем функцию температуры LcdClear(); // очищаем LCD if(min==1) // если минус { sprintf(lcd_buf,"-%u.%u\x80C",temper_int/10,temper_int%10); //вывод отрицательной температуры }else { sprintf(lcd_buf,"+%i.%d\x80C",temper_int/10,temper_int%10); // вывод положительной } LcdStringBold(1,2); LcdUpdate(); // вывод на дисплей };
вот вариант с точностью до 0.1, правда на дисплее от Nokia 3310. Здесь датчик подключён на PD2.
/***************************************************** ATmega8 4,000000 MHz *****************************************************/ #include <mega8.h> // 1 Wire Bus functions #asm .equ __w1_port=0x12 ;PORTD .equ __w1_bit=2 #endasm #include <1wire.h> // DS1820 Temperature Sensor functions #include <ds18b20.h> #include <delay.h> // maximum number of DS1820 devices // connected to the 1 Wire bus #define MAX_DS18B20 3 // number of DS1820 devices // connected to the 1 Wire bus unsigned char ds18b20_devices; // DS1820 devices ROM code storage area, // 9 bytes are used for each device // (see the w1_search function description in the help) unsigned char ds18b20_rom_codes[MAX_DS18B20][9]; #include <3310lcd.c> #include <stdio.h>
// Declare your global variables here float temper; int temper_int,temper_fl,min=0;
void temperature(void) // функция по работе с термо-датчиком { temper=ds18b20_temperature(&ds18b20_rom_codes[0][0]); temper_int=temper; // отбор целой части от температуры if(temper<0) // при отрицательной температуре { temper_fl=(temper-temper_int-0.0625)*10; // дробная часть temper_int=-((temper_int*10)+temper_fl); // температура*10 min=1; // минус }else // при положительной { temper_fl=(temper-temper_int)*10; // дробная часть temper_int=(temper_int*10)+temper_fl;// температура*10 min=0; // плюс }
} void main(void) { // Determine the number of DS1820 devices // connected to the 1 Wire bus ds18b20_devices=w1_search(0xf0,ds18b20_rom_codes); ds18b20_init(0,-35,35,DS18B20_12BIT_RES); // переключения термометра в 12 битный режим
LcdInit(); // LCD module initialization
while (ds18b20_devices>0 ) { // Place your code here delay_ms(500); temperature(); // вызываем функцию температуры LcdClear(); // очищаем LCD if(min==1) // если минус { sprintf(lcd_buf,"-%u.%u\x80C",temper_int/10,temper_int%10); //вывод отрицательной температуры }else { sprintf(lcd_buf,"+%i.%d\x80C",temper_int/10,temper_int%10); // вывод положительной } LcdStringBold(1,2);
Добавил к данной схеме два светодиода зеленый и красный на порт PC0 и PC1 соответственно; и данные температуры пересылаются по Uart. Если датчик подключен, то моргает зеленый, если нет, то красный. Подправил прогу теперь есть проверка на подключения датчика, то есть датчик можно включить после подачи питания. Если что-то не понятно, пишите на ящик. собственно программа:
#include <mega8.h> //библиотека ввода\вывода #include <delay.h> //библиотека задержки #asm //сообщаем куда подключен датчик .equ __w1_port=0x15; PORTC .equ __w1_bit=3 #endasm #asm //сообщаем куда подключён экран .equ __lcd_port=0x18 #endasm #include <lcd.h> //библиотека для LCD #include <1wire.h> //библиотека работы с 1Wire #include <ds18b20.h> //библиотека для работы с датчиком ds18b20 #include <stdio.h> char lcd_buffer[33]; //создаем масcив с данными для экрана void usart_tx(unsigned char data) { // передача по UART while ( !(UCSRA & (1<<5)) ); //ждём очистки регистра данных UART UDR=data; //отправить } void main(void) { unsigned char devices; //переменная в которой количество присоединённых датчиков int temp; //переменная для хранения температуры lcd_init(8); //инициализация LCD, и говорим что он на 8 символов в каждой стоке UCSRA=0x00; UCSRB=0x08; //настройка Uart на передачу, скорость 2400 UCSRC=0x86; UBRRH=0x00; UBRRL=0xCF; DDRC.0=1; DDRC.1=1; //настройка порта PС0 и PС1 на выход devices=w1_init(); //инициализация датчика while(devices==0) /* проверка на подключение датчика если его нет,то будем быстро мигать (период 0.3 сек) и передавать по UART 241 до устранения неисправности*/ { delay_ms(150); // пауза 150 мС PORTC.1 = 1; // вЫкл светодиод delay_ms(150); // пауза 150 мС PORTC.1 = 0; // вкл светодиод sprintf(lcd_buffer,"Error NoConnect!"); //задаем массив для выдачи ошибки lcd_clear(); //чистим дисплей перед выводом lcd_puts(lcd_buffer); //Выводим Error No Connect! while ( !(UCSRA & (1<<5)) ); //ждём остки регистра данных UART UDR=241; //отправляем 241 devices=w1_init(); //ищем датчики }; while(devices>0) //бесконечный цикл, если датчик подключен { PORTC.0=0; //гасим светодиод temp=ds18b20_temperature(0); //читаем температуру usart_tx(temp); //отправляем на комп результат температуры if (temp>1000) { //если датчик выдаёт больше 1000 temp=4096-temp; //отнимаем от данных 4096 temp=-temp; //и ставим знак "минус" } usart_tx(temp); //отпровляем на комп результат температуры sprintf(lcd_buffer,"\xAF\xAA\xAA 1A61t=%i.%u\xdfC",temp,temp%1); //задаем массив реквизитов lcd_clear(); //чистим дисплей перед выводом lcd_gotoxy(0,0); lcd_puts(lcd_buffer); //выводим массив на LCD devices=w1_init(); //инициализация датчика while(devices==0) /* проверка на подключение датчика если его нет, то будем быстро мигать (период 0.3 сек) и передавать по UART 241 до устранения неисправности*/ { delay_ms(150); // пауза 150 мС PORTC.1 = 1; // выкл светодиод delay_ms(150); // пауза 150 мС PORTC.1 = 0; // вкл светодиод sprintf(lcd_buffer,"Error NoConnect!"); //задаем массив выдачи об ошибки lcd_clear(); //чистим дисплей перед выводом lcd_puts(lcd_buffer); //Выводим Error No Connect! while ( !(UCSRA & (1<<5)) ); //ждём очистки регистра данных UART UDR=241; //отправляем 241 devices=w1_init(); //ищем датчики }; PORTC.0=1; //зажигаем светодиод delay_ms(150); // пауза 150 мС }; }
25 Onkel (19.02.2010 14:12) касательно DS18B20 - работает он у меня на проге сгенеренной Code Vision, но имею следующую засаду - мк (атмега8) дает команду ds18b20_temperature(NULL) ( у меня он один висит на 1wire) и висит 746 мс, а мне надо байты принимать/передавать, ацп запускать и прочее. Ну думаю, можно дать команду "меряй", а потом быстренько считать. А вот таких команд по раздельности в CV нет. Пробовал следующее
ds18b20_init(Null,18,25,3); // инициализация проходит, возвращает 1 как положено w1_write(0xcc); // scip rom, все равно на шине он один w1_write(0x44); // команда мерять Т w1_write(0xBE); // read scratchpad Tlow=w1_read(); // считываю в переменную мл. разряд результата преобразования Thigh=w1_read();// считываю в переменную ст. разряд результата преобразования w1_init();// обрубаю передачу, больше мне ничего не нужно от термометра
ну так ничего не считывается - обе переменные FF, пробовал и с задежками между всеми командами.
Ошибка у меня или как - то по - другому надо обмен с DS делать?
Всё правильно. Только эта функция не случайно висит 750мс - это максимальное время преобразования температуры датчиком. Поэтому я делаю почти так же только после команды преобразования температуры (w1_write(0x44); // команда мерять Т) иду делать то, что мне нужно, а считывание температуры произвожу после того как пройдет приблизительно время преобразования. Можно сделать две отдельные функции - одну на запрос преобразования, вторую на считывание.