Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

termoПродолжаем осваивать периферию, на очереди измерение температуры. Рассмотрим вариант измерения, при помощи датчика температуры DS18b20.

Характеристики датчика: диапазон измерения от -55 до +125°С. Точность измерения ±0,5°С гарантируется в диапазоне от -10 до +85°С. Возможность измерения с разрешением 9, 10, 11 и 12 бит, т.е. с шагом 0,5; 0,25; 0,125; 0,0625°С. Для обмена информацией с AVR микроконтроллером используется 1-Wire протокол. Каждый датчик имеет свой уникальный адрес, поэтому имеется возможность посадить на шину сразу несколько датчиков.

les12-2

Для сборки схемы понадобится жк дисплей, датчик и резистор на 4,7кОм. Теперь перейдем непосредственно к прошивке.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <mega8.h>
#include <delay.h>
// 1 Wire Bus functions
#asm
   .equ __w1_port=0x18 ;PORTB
   .equ __w1_bit=2
#endasm
#include <1wire.h>
#include <ds18b20.h>
 
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x12 ;PORTD
#endasm
#include <lcd.h>
#include <stdio.h> 
 
char lcd_buf[17];
void main(void)
{
 
float temper;  
lcd_init(16);   
w1_init();
ds18b20_init(0,-20,50,DS18B20_12BIT_RES); 
 
while(1)                 
      {
          temper=ds18b20_temperature(0);  
          sprintf(lcd_buf,"t=%.1f\xdfC",temper);    
          lcd_clear();                
          lcd_puts(lcd_buf);        
          delay_ms(1500);              
      }; 
}

Теперь обо всем по порядку:

1
2
3
4
#asm
   .equ __w1_port=0x18 ;PORTB
   .equ __w1_bit=2
#endasm

Данный код означает, что датчик подключен к порту В, PB2 ножке

1
2
#include <1wire.h>
#include <ds18b20.h>

Используется протокол 1wire, тип датчика ds18b20

1
2
3
float temper;  
w1_init();
ds18b20_init(0,-20,50,DS18B20_12BIT_RES);

Переменная temper (с плавающей точкой) используется для хранения температуры,
w1_init(); — ищем датчик,
ds18b20_init(0,-20,50,DS18B20_12BIT_RES); — настройка датчика: 0-номер датчика, -20 -нижний предел измерения, 50 — верхний предел измерения,
DS18B20_12BIT_RES используется 12 битный режим(с шагом 0,0625°С). В принципе настройку можно не производить, по умолчанию выставлен 12 битный режим. Показано лишь для того, чтобы вы могли самостоятельно изменить режим измерения, если это понадобится.

1
2
3
4
5
6
          temper=ds18b20_temperature(0);  
 
          sprintf(lcd_buf,"t=%.1f\xdfC",temper);    
          lcd_clear();                
          lcd_puts(lcd_buf);        
          delay_ms(1500);

temper=ds18b20_temperature(0); — читаем значение температуры с датчика
sprintf(lcd_buf,»t=%.1f\xdfC»,temper); преобразовываем к понятному для lcd виду %.1f — вывод числа с плавающей точкой 1 знак после запятой, не забываем в свойствах проекта указать (s)printf features float.
\xdf — вывод на экран значка градуса.

В результате должно получиться нечто похожее
les12-4

Отрицательной температуры поблизости не было :D, поэтому попробовал остудить бутылочкой соуса из холодильника, результат что то не сильно впечатлил.
les12-5

Зато от нагрева рукой, температура довольно быстро повысилась.
les12-3
Проект доступен тут
Проект для DS18s20
Проект для двух датчиков
Проект для DS18b20 на семисегментниках
Проект Алексея(Alyes)для Atmega16 и шести сегментов + бонус видео устройства

259 комментариев: Урок 12. Измерение температуры при помощи AVR. Простой термометр на AVR.

  • #include
    #include
    #include
    #include
    #include
    #include
    #asm
    .equ __lcd_port=0x15 ;PORTC
    #endasm
    #define FIRST_ADC_INPUT 0
    #define LAST_ADC_INPUT 0
    unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
    #define ADC_VREF_TYPE 0x40
    float result;

    // ADC interrupt service routine
    // with auto input scanning
    interrupt [ADC_INT] void adc_isr(void)
    {
    static unsigned char input_index=0;
    // Read the AD conversion result
    adc_data[input_index]=ADCW;
    // Select next ADC input
    if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
    input_index=0;
    ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    // Start the AD conversion
    ADCSRA|=0x40;
    }

    char lcd_buf[16];

    void main(void)
    {
    float temper;

    PORTA=0x00;
    DDRA=0x00;

    PORTB=0x00;
    DDRB=0x00;

    PORTC=0x00;
    DDRC=0x00;

    PORTD=0x00;
    DDRD=0x00;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    SFIOR=0x00;

    // ADC initialization
    // ADC Clock frequency: 125,000 kHz
    // ADC Voltage Reference: AVCC pin
    // ADC Auto Trigger Source: ADC Stopped
    ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
    ADCSRA=0xCE;

    // 1 Wire Bus initialization

    w1_init();
    ds18b20_init(0,-20,50,DS18B20_12BIT_RES);
    // Alphanumeric LCD initialization

    lcd_init(16);

    // Global enable interrupts
    #asm(«sei»)

    while (1)
    {

    temper=ds18b20_temperature(0);
    if (temper>1000)
    {
    temper=4096.0-temper;
    temper=-temper;
    }
    lcd_clear();
    lcd_gotoxy(0,0);
    result=((5.00*adc_data[0])/1024.00);
    sprintf(lcd_buf,»U=%.2fV»,result);
    lcd_puts(lcd_buf);
    lcd_gotoxy(0,1);
    sprintf(lcd_buf,»t=%.1f\xdfC»,temper);
    lcd_puts(lcd_buf);
    delay_ms(2000);

    }

    }

  • Разнесите измерение температуры и измерение напряжения по времени, а то получается что датчик измеряет температуры и в этот момент его останавливает прерывание от АЦП.

  • Вы уж извините, но я новичок в контроллерах, можете посоветовать как реализовать это разнесение во времени (если Вас не затруднит — кусочек кода как это правильно делается)? Спасибо!

  • #include <mega8.h>
    #include <lcd.h>
    #include <delay.h>
     
    #asm
    .equ __lcd_port=0×15 ;PORTC
    #endasm
     
    #define ADC_VREF_TYPE 0x40
    // Read the AD conversion result
    unsigned int read_adc(unsigned char adc_input)
    {
    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    // Start the AD conversion
    ADCSRA|=0x40;
    // Wait for the AD conversion to complete
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
    }
     
    char lcd_buf[16];
     
    void main(void)
    {
    float temper;
     
    PORTB=0x00;
    DDRB=0x00;
    PORTD=0x00;
    DDRD=0x00;
     
    // ADC initialization
    // ADC Clock frequency: 125,000 kHz
    // ADC Voltage Reference: AVCC pin
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0x86;
     
    // 1 Wire Bus initialization
    w1_init();
    ds18b20_init(0,-20,50,DS18B20_12BIT_RES);
    // Alphanumeric LCD initialization
     
    lcd_init(16);
     
    // Global enable interrupts
    #asm(«sei»)
     
    while (1)
          {
          temper=ds18b20_temperature(0);
          lcd_clear();
          lcd_gotoxy(0,0);
          result=((5.00*read_adc(0))/1024.00);
          sprintf(lcd_buf, "U=%.2fV",result);
          lcd_puts(lcd_buf);
     
          lcd_gotoxy(0,1);
          sprintf(lcd_buf,"t=%.1fxdfC",temper);
          lcd_puts(lcd_buf);
          delay_ms(2000);
     
          }
    }
  • Подскажите пожалуйста как отображать на ЖКД температуру от 3х датчиков одновременно. Скачал Ваш исходник для двух датчиков, добавил следующую строку для 3го

    ds18b20_init( &ds18b20_rom_codes[2][0], 0, 60, DS18B20_12BIT_RES );

    изменил строку — unsigned char ds18b20_rom_codes[3][9];

    и изменил строку вывода — sprintf( lcd_buf,»t1=%.1f\xdfC t2=%.1f\xdfC t3=%.1f\xdfC», ds18b20_temperature(&ds18b20_rom_codes[0][0]),ds18b20_temperature(&ds18b20_rom_codes[1][0] ,ds18b20_temperature(&ds18b20_rom_codes[2][0]) );

    Компилирую, пишет, что много аргументов в вызываемой функции, при этом ссылаясь на строку вывода

  • Может потому что скобки не хватает, после 2 переменной

  • Да, Вы правы- добавил скобку теперь отображается 3 значения. Только 3й -9999 и то это если в протеус не подцепляю 3й датчик. Когда подключаю 3й, то два из них показывает -9999, а третий правильную температуру. Перепробовал в протеусе различные схемы подключения датчиков — ничего(((. Могу приложить код. А как приложить проект в протеус?

  • Добрый день, подскажите новичку пожалуйста, что я делаю не так?
    Хочу поставить условия, что если температура меньше 13 градусов на одном из датчиков, то на определённые порты выводится лог. единица
    #include
    #include
    // 1 Wire Bus functions
    #asm
    .equ __w1_port=0x18 ;PORTB
    .equ __w1_bit=2
    #endasm
    #include
    #include
    #include
    unsigned char P=0;
    unsigned char Z=0;
    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[2][9];

    // Alphanumeric LCD Module functions
    #asm
    .equ __lcd_port=0x12 ;PORTD
    #endasm
    #include

    void main(void)
    {
    float temper;
    char lcd_buf[33];

    PORTB=0x00;
    DDRB=0x00;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;

    // Determine the number of DS1820 devices
    // connected to the 1 Wire bus
    ds18b20_devices=w1_search(0xf0,ds18b20_rom_codes);

    ds18b20_init( &ds18b20_rom_codes[0][0], 0, 60, DS18B20_12BIT_RES );
    ds18b20_init( &ds18b20_rom_codes[1][0], 0, 60, DS18B20_12BIT_RES );

    lcd_init(16);

    while (1)
    {
    temper=ds18b20_temperature(0);
    sprintf( lcd_buf,»t=%.1f\xdfC t2=%.1f\xdfC», ds18b20_temperature(&ds18b20_rom_codes[0][0]),ds18b20_temperature(&ds18b20_rom_codes[1][0]) );
    P=ds18b20_temperature(&ds18b20_rom_codes[0][0]);
    Z=ds18b20_temperature(&ds18b20_rom_codes[0][0]);
    if(P>13) PORTB.1=1;
    else PORTB.1=0;
    if(Z>13) PORTB.3=1;
    else PORTB.3=0;
    lcd_gotoxy(0,0);
    lcd_puts( lcd_buf );

    }
    }

  • порты не настроены и ставьте скобки с if

  • Спасибо вам огромное. вы спасли меня от мучений на форумах.

  • Я хочу подключить несколько (15 датчиков) К контроллеру. Как понять какой из-них будет определен как «первый», «второй» и т.д.? По схеме-то, все они подключаются параллельно.

    И второй вопрос — как далеко (физически) датчики могут находиться от контроллера? Мне нужно измерять температуру в разных помещениях, и максимальное удаление от контроллера может быть до 200 метров.

  • Теоретически до 300м, но для этого нужен соответствующий кабель и топология, думаю дешевле организовать обмен по радиоканалу. Посмотрите проект для двух датчиков
    ds18b20_init( &ds18b20_rom_codes[0][0], 0, 60, DS18B20_12BIT_RES );
    для первого
    ds18b20_init( &ds18b20_rom_codes[1][0], 0, 60, DS18B20_12BIT_RES );
    для второго
    по аналогии остальные

  • Спасибо за ответ. С расстоянием — понятно, буду пробовать. А вот с номерами датчиков не все ясно. Я не понимаю как контроллер понимает, что датчик в комнате №1 — это «первый» датчик, в комнате №2 — «второй» и т.д. Нигде явно не уписываются номера датчиков с привязкой к конкретному физическому датчику. Все датчики DS18B20 подключены параллельно друг другу. В них-же нет возможность явно указать адрес, как например в датчиках LM75.
    Правильно ли я понимаю, что номер датчика будет определен по внутреннему 64-битному коду, который зашит в датчик ds18b20 на заводе, и для того, что-б понять какой датчик под номером «1» в программе соответствует физическому датчику №»1″, нужно будет «перебрать» руками все датчики и вычислить экспериментальным путем какой контроллером определяется как «первый», какой «второй» и т.д.?

  • У меня не было под рукой нескольких датчиков чтобы проверить, но я думаю что все именно так как вы написали.

  • Ясно. Проверю, расскажу! 🙂 Спасибо!

  • Как подружить несколько датчиков в протеусе. По одному схема работает. Два выводит -99999 оба числа.

  • на самих датчиках в протеусе выставить разные адреса

  • Здравствуйте! Попробовал собрать проект, температуру так и не вывел! Думаю ладно, скачал архив, ещё интереснее, на датчике установлено 27 градусов, а показывает 213!
    Вы хоть проверяете то что делаете?!

  • каждый из выложенных проектов проверен

  • Добрый вечер. проблема,вместо температуры выводит — t=1f*C
    #include
    #include
    // 1 Wire Bus functions
    #asm
    .equ __w1_port=0x18 ;PORTB
    .equ __w1_bit=2
    #endasm
    #include

    // DS1820 Temperature Sensor functions
    #include

    // Alphanumeric LCD Module functions
    #asm
    .equ __lcd_port=0x1B ;PORTA
    #endasm
    #include
    #include

    char lcd_buf[17];
    void main(void)
    {
    // Declare your local variables here
    float temper;
    // Input/Output Ports initialization
    // Port A initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTA=0x00;
    DDRA=0x00;

    // Port B initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTB=0x00;
    DDRB=0x00;

    // Port C initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTC=0x00;
    DDRC=0x00;

    // Port D initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTD=0x00;
    DDRD=0x00;

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Normal top=FFh
    // OC0 output: Disconnected
    TCCR0=0x00;
    TCNT0=0x00;
    OCR0=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer 1 Stopped
    // Mode: Normal top=FFFFh
    // OC1A output: Discon.
    // OC1B output: Discon.
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer 1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: Timer 2 Stopped
    // Mode: Normal top=FFh
    // OC2 output: Disconnected
    ASSR=0x00;
    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    // INT2: Off
    MCUCR=0x00;
    MCUCSR=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=0x00;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    SFIOR=0x00;
    lcd_init(16);
    w1_init();
    ds18b20_init(0,-20,50,DS18B20_12BIT_RES);

    while (1)
    {
    temper=ds18b20_temperature(0);
    sprintf(lcd_buf,»t=%.1f\xdfC»,temper);
    lcd_clear();
    lcd_puts(lcd_buf);
    delay_ms(1500);
    };
    }

  • скопируйте строку sprintf из исходника

  • .Куда скопировать?

  • Я в этом нуб,по этому могу не понять краткости изложений

  • Если просто копировать- то одно и тоже

  • Получилось с помощью этого — «не забываем в свойствах проекта указать (s)printf features float.». Только теперь другая проблемы,выводит t=-9999

  • если используете версию 2+, то датчик подключается в свойствах проекта, там же где меняли (s)printf features float, там есть вкладка libraries, на ней нужно указать ножки к которым подключен датчик

  • версия 1.24

  • возможно в протеусе стоит частота 1мгц, проект рассчитан на 8мгц. поменяйте в свойствах камня

  • Здравствуйте. Подскажите пожалуйста новичку. Я вот не могу понять, когда мы только создаем проект в CV AVR, выибираем там дисплей, указываем что к порту D, потом переходим во вкладку 1 wire? Ставим галочку использовать, указываем что датчик ds18b20 а битность указываем 0? У меня вот именно тут проблема.

  • это не битность, а номер ножки к которой будете цеплять датчик

  • Приветствую Вас не могу разобраться, ругается на ds18b20_init(0,-30,99,DS18B20_12BIT_RES);

  • При построении проекта, появляется ошибка Error(s) occured during assembly. И в сообщениях, две ошибки . Invalid redefinition of ‘ _ w1 port ‘ и Invalid redefinition of ‘ _ w1 bit ‘Сталкивался кто с таким?

  • Может что-то в настройках портов? Можете все настройки сказать какие устанавливать? Порты нужно ли какие-то настраивать?

  • Приветствую. Выручит кто может, Делаю устройство для включения подогрева бака по температуре, начинаю тестить в протеусе так, программа дает сбой начинает отрабатывать при не заданных параметрах.
    w1_init();
    ds18b20_init(0,-30,100,DS18B20_12BIT_RES);
    temper=ds18b20_temperature(0);

    while(1)
    {
    temper=ds18b20_temperature(0);
    if(temper>1000)
    {
    temper=4096-temper;
    temper=-temper;
    };

    if (temper=5)
    {
    PORTB.7=0;
    };

    if (temper==5)
    {
    PORTB.4=1;
    delay_ms(100);
    PORTB.4=0;
    };

    if (temper==10)
    {
    PORTB.5=1;
    delay_ms(100);
    PORTB.5=0;
    };

  • тут ошибка
    if (temper=5)
    {
    PORTB.7=0;
    };

  • Ошибку исправил, но все равно при проверке работы в протеусе, странная ошибка возникает . Уже кучу форумов «обошел», а понять не могу даже на самом простом кусочке кода тестить пытаюсь. Вместо отрабатывания по заданной отрабатывает само по себе. Проект на аттини делаю.

  • Вместо того, чтобы «обходить» форумы, можно посмотреть в отладке где отваливается. Ведь это так просто тыкнуть кнопочку и пройтись по шагам.

  • Просто в отладчике не знаю как посмотреть, код при изменяющихся данных с датчика. Проблема возникает, без какой либо последовательности, тест проводил только протеусе. В железе не проводил тест хотя железо уже собрал.

  • А еще спросить хотел. С тем вопросом разберусь. Когда генерирую код на ATTINY 2313, ругается при компиляции на «ds18b20_temperature(0)» и на «ds18b20_init», а также просит переменную вынести из основной функции CAVR 1.27. Вот это до меня уж вообще ни как не доходит. А когда переписываю Ваш код проблем не возникает 🙁 🙁

  • сложно так ответить, закиньте проект целиком на какой нить яндекс диск, а сюда киньте ссылку

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика