Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Микропроцессорная курсовой.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
935.94 Кб
Скачать

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 і подивимося основні моменти, які нам знадобляться:

        1. Датчик може забезпечувати 9-, 10-, 11-, 12-ти бітове розділення вимірювання температури в градусах Цельсія. Це розділення ми можемо вибирати, записуючи дані в конфігураційний регістр датчика (за замовчуванням 12-бітове розділення).

        2. Вимірює в діапазоні -55...+125 оС. З точністю 0.5 градуса.

  1. На одиницю коду перетворюваного значення температури доводиться 0.0625оС.

  2. При читанні даних з датчика ми приймаємо 9 байт даних, з яких ми будемо брати 0-й і 1-й, молодший і старший байт температури відповідно. У старшому байті в бітах 11-15 міститься інформація про знак температури (якщо в цих бітах одиниця, тоді температура нижче нуля).

  3. Час перетворення температури з 12-бітною точністю займає max 750 мс. Тобто це час потрібно буде почекати після виклику команди перетворення температури (0х44) і тільки потім посилати таку команду.

  4. Після перетворення температури, перш ніж посилати таку команду потрібно ще раз послати імпульс скидання (Reset pulse) і отримати відповідь імпульс (Presence Pulse).

Приклад схеми пристрою наведений на рис. 13. Данний пристрій вимірює температуру за допомогою двох датчиків DS18B20 та виводить результат на LCD дисплей. Програму, що реалізує даний пристрій зроблену у середовищі CodeVisionAVR.

        1. #include <mega8.h>

        2. #include <1wire.h>

        3. #include <ds18b20.h>

        4. #define MAX_DS1820 8

        5. unsigned char rom_codes[MAX_DS1820][9];

        6. #include <stdio.h>

  1. char lcd_buffer[33]; // буфер для температуры

  2. #include <delay.h>

  3. #include <alcd.h>

  4. unsigned char buf[33];// буфер для значений АЦП

  5. int temp[8]; int a;

  6. //--------------------------------------------------------------------------

  7. // Далее строки 13-39 настройка работы АЦП по входу 1 (РС1 или 24 лапка чипа

  8. #define FIRST_ADC_INPUT 1

  9. #define LAST_ADC_INPUT 1

  10. unsigned char adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];

  11. #define ADC_VREF_TYPE 0x20

  12. // ADC interrupt service routine

  13. // with auto input scanning

  14. interrupt [ADC_INT] void adc_isr(void)

  15. {

  16. static unsigned char input_index=0;

  17. // Read the 8 most significant bits

  18. // of the AD conversion result

  19. adc_data[input_index]=ADCH;

  20. PORTD=ADCH;// можно эту строку удалить, просто она выводит в порт результат АЦП (при

  21. настройке удобно)

  22. // Select next ADC input

  23. if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))

  24. input_index=0;

  25. ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;

  26. // Delay needed for the stabilization of the ADC input voltage

  27. delay_us(10);

  28. // Start the AD conversion

  29. ADCSRA|=0x40;

  30. }

  31. //----------все АЦП настроили ;) ------------------------------------------------------------

  32. // Timer1 output compare A interrupt service routine

  33. /*

  34. Именно таймером 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

// все...