- •Методичні вказівки
- •6.05080202 „Електронні системи”
- •6.05080102 «Фізична та біомедична електроніка»
- •Введення.
- •Початкові дані для проектування.
- •Приклади реалізації елементів мікропроцесорної
- •Робота із зовнішніми перериваннями мк avr.
- •2.2 Робота з таймерами/лічильниками мк avr
- •2.3 Робота мк avr з lcd дисплеєм.
- •2.4 Інтерфейс 1-Wire і температурний датчик ds18b20
- •Література
- •51918, М. Дніпродзержинськ
2.4 Інтерфейс 1-Wire і температурний датчик ds18b20
Шина 1-Wire приваблива, в першу чергу, тим, що використовує тільки одну лінію зв'язку. Розберемо 1-Wire детальніше. Для роботи цього інтерфейсу повинен бути один ведучій пристрій і один або кілька ведених. У кожного 1-Wire пристрою є 64-бітний унікальний код. Використовуючи який, ведучий визначає з яким з пристроїв на лінії він буде працювати. Але дізнатися цей код це окрема процедура, тому поки будемо вважати, що у нас всього один пристрій, підключений до шини - температурний датчик DS18B20.
Отже, щоб працювати з будь-яким пристроєм нам потрібно ініціалізувати його, послати йому команду і прийняти якісь дані. Розберемо як це можна зробити на шині 1-Wire.
Перший крок, щоб провести пошук пристроїв на лінії, відучий пристрій (у нашому випадку мікроконтролер) повинен утримувати на сигнальній лінії логічний "0" принаймні 480 мкс (так званий Reset Pulse), потім відпустити шину мінімум на 60мкс і після цього подивитися рівень на лінії. Якщо на лінії високий рівень - пристроїв 1-Wire не виявлено, якщо низький - є хоча б один пристрій (Presence Pulse).
Рисунок 10. – Процедура пошуку підключених пристроїв до інтерфейсу 1-Wire.
Другий крок, тепер ми повинні послати команду пристрою. Передача інформації розбита на тайм-слоти. Один тайм-слот служить для передачі одного біта команди та тривалість його знаходиться в діапазоні 60-120 мкс. Дані передаються, починаючи з молодшого біта. Для передачі логічного нуля МК утримує на лінії "0" мінімум 60мкс, а потім відпускає шину мінімум на 1мкс. Для передачі логічної одиниці МК утримує на лінії "0" мінімум 1 мкс, але не більше 15 мкс, а потім відпускає шину на час, що залишився для тайм-слота.
Рисунок 11. – Пересилка команди пристрою, що підключений до інтерфейсу 1-Wire.
Третій крок, прийом даних з пристрою 1-Wire. Щоб прийняти дані МК утримує на лінії "0" не менш 1 мкс, а потім відпускає шину, трохи чекає і дивиться стан лінії (зазвичай до 15-ї мікросекунди від початку тайм-слоти). Якщо на лінії "1" - означає передається "1", якщо "0" - значить "0".
Рисунок 12. – Процедура прийому даних з пристрою 1-Wire.
До чого слід поставитися серйозно так це до затримок. Потрібно керуватися наступним правилом: сигнали, які формує МК, необхідно формувати за необхідного мінімуму тривалості (трохи більше мінімально вказаної), а від сигналів пристрою потрібно чекати найгіршого варіанту. Також, якщо 1-Wire пристрій знаходиться далеко від МК, тоді може виникнути потреба зменшити величину опору підтягуючого резистора. Це пов'язано з тим, що подовжуючи лінію ми збільшуємо погонну ємність лінії, а отже і збільшуємо час повернення лінії в одиницю за рахунок підтягуючого резистора (наприклад, після Reset імпульсу ми відпускаємо шину і за рахунок цього резистора вона повертається в одиницю). У деякий момент цей час може виявитися більше ніж максимально необхідний для роботи з 1-Wire шиною і вся подальша передача інформації буде не вірна.
Для вимірювання температури будемо використовувати датчик DS18B20. Почнемо з того, що відкриємо Datasheet і подивимося основні моменти, які нам знадобляться:
Датчик може забезпечувати 9-, 10-, 11-, 12-ти бітове розділення вимірювання температури в градусах Цельсія. Це розділення ми можемо вибирати, записуючи дані в конфігураційний регістр датчика (за замовчуванням 12-бітове розділення).
Вимірює в діапазоні -55...+125 оС. З точністю 0.5 градуса.
На одиницю коду перетворюваного значення температури доводиться 0.0625оС.
При читанні даних з датчика ми приймаємо 9 байт даних, з яких ми будемо брати 0-й і 1-й, молодший і старший байт температури відповідно. У старшому байті в бітах 11-15 міститься інформація про знак температури (якщо в цих бітах одиниця, тоді температура нижче нуля).
Час перетворення температури з 12-бітною точністю займає max 750 мс. Тобто це час потрібно буде почекати після виклику команди перетворення температури (0х44) і тільки потім посилати таку команду.
Після перетворення температури, перш ніж посилати таку команду потрібно ще раз послати імпульс скидання (Reset pulse) і отримати відповідь імпульс (Presence Pulse).
Приклад схеми пристрою наведений на рис. 13. Данний пристрій вимірює температуру за допомогою двох датчиків DS18B20 та виводить результат на LCD дисплей. Програму, що реалізує даний пристрій зроблену у середовищі CodeVisionAVR.
#include <mega8.h>
#include <1wire.h>
#include <ds18b20.h>
#define MAX_DS1820 8
unsigned char rom_codes[MAX_DS1820][9];
#include <stdio.h>
char lcd_buffer[33]; // буфер для температуры
#include <delay.h>
#include <alcd.h>
unsigned char buf[33];// буфер для значений АЦП
int temp[8]; int a;
//--------------------------------------------------------------------------
// Далее строки 13-39 настройка работы АЦП по входу 1 (РС1 или 24 лапка чипа
#define FIRST_ADC_INPUT 1
#define LAST_ADC_INPUT 1
unsigned char adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
#define ADC_VREF_TYPE 0x20
// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the 8 most significant bits
// of the AD conversion result
adc_data[input_index]=ADCH;
PORTD=ADCH;// можно эту строку удалить, просто она выводит в порт результат АЦП (при
настройке удобно)
// 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;
}
//----------все АЦП настроили ;) ------------------------------------------------------------
// Timer1 output compare A interrupt service routine
/*
Именно таймером 1 выставляем время (интервалы) обновления информации на LCD,
41. в данном примере термометры и АЦП обновляются одновременно.
42. */
43. interrupt [TIM1_COMPA] void timer1_compa_isr(void)
44. {
45. // Place your code here
46. TCNT1H=0x00;
47. TCNT1L=0x00;
48. a=ADCH;
49. temp[0]=ds18b20_temperature(&rom_codes[1][0]);
-
50
temp[1]=ds18b20_temperature(&rom_codes[0][0]);
51
lcd_clear();
52
// стр. 57-78 пишем "холодно", "норма", "жарко"
53
if (temp[0]<20)
54
{
55
//lcd_clear();
56
sprintf(buf,"Cold!");//
57
lcd_gotoxy(10,1);
58
lcd_puts(buf);
59
}
60
if (temp[0]>=20&temp[0]<=30)
61
{
62
//lcd_clear();
63
sprintf(buf,"Norma");//
64
lcd_gotoxy(10,1);
65
lcd_puts(buf);
66
}
67
if (temp[0]>30)
68
{
69
//lcd_clear();
70
sprintf(buf,"Hot!");//
71
72
lcd_gotoxy(10,1);
lcd_puts(buf);
73
}
74
sprintf(lcd_buffer,"t=%i.%u\xdfC",temp[0],temp[0]%1);
75
76
lcd_gotoxy(0,0);
lcd_puts(lcd_buffer);
77
// строки 80-82 вывели датчик температуры 1 на дисплей
78
sprintf(lcd_buffer,"t=%i.%u\xdfC",temp[1],temp[1]%1);
79
lcd_gotoxy(0,1);
80
lcd_puts(lcd_buffer);
81
// строки 85-87 вывели датчик температуры 2 на дисплей
82
sprintf(buf,"U=%d.%u",a/51,a%100);// АЦП - делитель сам выставляй
83
lcd_gotoxy(10,0);
84
lcd_puts(buf);
85
delay_ms(50);
86
// строки 90-93 результат АЦП вывели на дисплей (только 8-старших битов)
87
}
88
//------------------------- основное тело программы -----------------------
89
void main(void)
90
{
91
unsigned char devices;
92
DDRD=0xff;
93
PORTD=0x00;
94
// настраиваем таймер 1
95
TCCR1A=0x00;
96
TCCR1B=0x03;
97
TCNT1H=0x00;// со скольки считаем - старший регистр
98
TCNT1L=0x00;// со скольки считаем - младший регистр
99
OCR1AH=0x00;// до скольки считаем - старший регистр
100
OCR1AL=0x08;// до скольки считаем - младший регистр
101
102
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10; // маска таймера (обязательно!)
103
ADMUX=FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff);
104
ADCSRA=0xCC;
105
lcd_init(16);// ну..., это понятно
106
delay_ms(200);
107
devices=w1_search(0xf0,rom_codes); // и сколько же у нас девайсов?
108
sprintf(lcd_buffer," devices=%u",devices);// а вот мы и видим число подключенных дивайсов!
109
lcd_clear();
110
lcd_puts(lcd_buffer);
111
delay_ms(2000);
112
// Global enable interrupts
113
#asm("sei")
114
while (1)
115
{
116
};
117
}
118
// все...
