Как совместить 2 проекта: Частотомер и Термометр на DS18B20

Модератор: boogyman

Как совместить 2 проекта: Частотомер и Термометр на DS18B20

Сообщение:#1  Сообщение Sergey F » 13 мар 2014, 14:42

Здравствуйте!
Помогите пожалуйста совместить два проекта: ЧАСТОТОМЕР и ТЕРМОМЕТР (DS18B20). Необходима контролировать одновременно температуру радиатора и частоту оборотов кулера.
Код:
Код: Выделить всё
// Измерение частоты сигнала с помощью микроконтроллеров AVR. Простой частотомер.
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#define F_CPU 8000000UL      
volatile unsigned int edgecounter = 0, counter = 0;

unsigned char Temp_H = 0,Temp_L = 0,OK_Flag = 0,temp_flag;

// Обработчик прерывания по переполнению Т0, вызывается 4000 раз в секунду
ISR(TIMER0_OVF_vect)
{
TCNT0 = 6; // Счетчик Т0 начинает считать с 6, т.к. 1MHz/(256-6) = 4000Hz
counter++;
}
// Обработчик внешнего прерывания
ISR(INT0_vect)
{
edgecounter++;
}

/*** Инициализация DS18B20 ***/
unsigned char DS18B20_init(void)
{
PORTC &= ~(1 << PC0); // устанавливаем низкий уровень
DDRC |= (1 << PC0);
_delay_us(490);
DDRC &= ~(1 << PC0);
_delay_us(68);
OK_Flag = (PINC & (1 << PC0)); // ловим импульс присутствия датчика
// если OK_Flag = 0 датчик подключен, OK_Flag = 1 датчик не подключен
_delay_us(422);
return OK_Flag;
}

/*** Функция чтения байта из DS18B20 ***/
unsigned char read_18b20(void)
{
unsigned char i;   
unsigned char dat = 0;
for(i = 0;i < 8;i++)
{      
DDRC |= (1 << PC0);
_delay_us(2);       
DDRC &= ~(1 << PC0);
_delay_us(4);       
dat = dat >> 1;      
if(PINC & (1 << PC0))
{         
dat |= 0x80;
}
_delay_us(62);
}   
return dat;
}

/*** функция записи байта в DS18B20 ***/
void write_18b20(unsigned char dat)
{
unsigned char i;   
for(i = 0;i < 8;i++)
{
DDRC |= (1 << PC0);
_delay_us(2);            
if(dat & 0x01)
{
DDRC &= ~(1 << PC0);   
}
else
{
DDRC |= (1 << PC0);
}
dat = dat >> 1;
_delay_us(62);
DDRC &= ~(1 << PC0);
_delay_us(2);
}   
}

// Функции работы с LCD
#define RS PD0
#define EN PD1
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}

// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')

lcd_data(*string);
string++;
}
}

// Функция вывода переменной
void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
 switch(nDigit)
 {
 case 4: lcd_data((value/1000)+'0');
 case 3: lcd_data(((value/100)%10)+'0');
 case 2: lcd_data(((value/10)%10)+'0');
 case 1: lcd_data((value%10)+'0');
 }
}
// Функция инициализации LCD
void lcd_init(void)
{
_delay_ms(50); // Ожидание готовности ЖК-модуля

// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);

// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5);

lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}

int main(void)
{
PORTD = 0x00; // Настраиваем входы/выходы
DDRD = 0b11110011;

TCCR0 |= (1 << CS01); // Предделитель на 8, частота таймера 1 MHz
TIMSK |= (1 << TOIE0); // Разрешаем прерывание от таймера Т0

GICR |= (1 << INT0); // Разрешаем внешнее прерывание на входе INT0
MCUCR |= (1 << ISC01)|(1 << ISC00); // Внешнее прерывание формируется по переднему фронту

unsigned int tempint = 0,tempint1,tempint2,tempint3; // переменные для целого значения температуры
unsigned int temppoint = 0,temppoint1; // переменные для дробного значения температуры

sei(); // Глобально разрешаем прерывания
   
lcd_init(); // Инициализация дисплея

lcd_com(0x01);
lcd_string(0x80, "F =      Hz");
lcd_string(0xC0, "T =       C");

while(1)
{

// Выводим показания на дисплей
if(counter == 4000)
{
lcd_com(0x84);
lcd_num_to_str(edgecounter, 4);
counter = 0;
edgecounter = 0;      
}

if(OK_Flag == 1) // если датчик не ответил
{
// ставим прочерки во всех разрядах
lcd_string(0xC4, "  NO  ");
}

DS18B20_init();        // инициализация DS18B20
write_18b20(0xCC);     // проверка кода датчика
write_18b20(0x44);     // запуск температурного преобразования
_delay_ms(1000);
DS18B20_init();        // инициализация DS18B20
write_18b20(0xCC);     // проверка кода датчика
write_18b20(0xBE);     // считываем содержимое ОЗУ
Temp_L = read_18b20(); // читаем первые 2 байта блокнота
Temp_H = read_18b20();
temp_flag = 1;         // флаг знака температуры равен 1(плюс)

if(Temp_H &(1 << 3))   // проверяем бит знака температуры на равенство единице
{         
signed int tmp;
temp_flag = 0;      // флаг знака равен 0(минус)
tmp = (Temp_H << 8) | Temp_L;
tmp = -tmp;
Temp_L = tmp;
Temp_H = tmp >> 8;
}      

tempint = ((Temp_H << 4) & 0x70)|(Temp_L >> 4); // вычисляем целое значение температуры
tempint1 = tempint % 1000 / 100; 
tempint2 = tempint % 100 / 10; 
tempint3 = tempint % 10;       
temppoint = Temp_L & 0x0F; // вычисляем дробное значение температуры
temppoint = temppoint * 625;       // точность температуры
temppoint1 = temppoint / 1000;       

if(temp_flag == 0) // если флаг знака температуры равен 0, в первом разряде ставим минус
lcd_string(0xC4, "-");

lcd_com(0xC4);
lcd_num_to_str(tempint1, 1);
lcd_com(0xC5);
lcd_num_to_str(tempint2, 1);
lcd_com(0xC6);
lcd_num_to_str(tempint3, 1);
lcd_string(0xC7, ".");
lcd_com(0xC8);
lcd_num_to_str(temppoint1, 1);

}
}
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Как совместить 2 проекта: Частотомер и Термометр на DS18

Сообщение:#2  Сообщение AntonChip » 13 мар 2014, 17:51

Исправить if(counter == 4000)
на if(counter > 4000)

еще неправильно показывает минусовые температуры
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 202
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Как совместить 2 проекта: Частотомер и Термометр на DS18

Сообщение:#3  Сообщение Sergey F » 13 мар 2014, 18:00

Хорошо исправлю.
А про температуру я знаю.
Спасибо!
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Как совместить 2 проекта: Частотомер и Термометр на DS18

Сообщение:#4  Сообщение Sergey F » 13 мар 2014, 18:25

Спасибо большое!
Проверил в Протеусе и на железе - всё работает.
Температуру исправил. Теперь буду добавлять ещё 1 канал термометра и частотомера, думаю проблем не будет.
Ещё раз большое спасибо!
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Как совместить 2 проекта: Частотомер и Термометр на DS18

Сообщение:#5  Сообщение AntonChip » 13 мар 2014, 21:35

Пожалуйста!
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 202
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров


Вернуться в Микроконтроллеры AVR

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

cron
Rambler's Top100