Всем привет.Есть такая проблема.Делаю терморегулятор.Есть программа написанная на СИ и есть схема в протеусе. Все вроде компилируется и ошибок нигде не выдает.Но не работает приборчик.И походу нет данных с датчика температуры.Помогите найти ошибку.!!!!Очень надо.В архиве есть все исходники.
/*
* Application1.c
* Author: Александр
*/
#define F_CPU 4000000UL
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#define PORTB_MASK 0x01 // zdes ispolzuem PB0 kak liniju dannih dlja datcika
#define GISTERESIS 30
void port_ini(void)
{
PORTB=0x00;
DDRB=0xFF;
}
//---Функци посылки RESET PULSE - датчику-----------------
unsigned char present_ds18b20(void)
{ unsigned char res;
DDRB|= PORTB_MASK; // Далее такого рода конструкция означает
// DDRB = DDRB | PORTB_MASK, т.е. DDRB = (xxxxxxxx | 00000001) = xxxxxxx1
_delay_ms(485); //Pause 480mks
DDRB&=~PORTB_MASK; // Далее такого рода конструкция означает
// DDRB = DDRB & ~PORTB_MASK, т.е. DDRB = (xxxxxxxx & 11111110) = xxxxxxx0
_delay_us(65); //Pause 70mks
if ((PINB&PORTB_MASK) == 0x00) // Если в PB0 0 , т.е. получен ответ от датчика present и возвращаем 1
res=1; //if present, res=1
else res=0; // else возвращаем 0
_delay_ms(420); //pause 410mks
return res;
}
//----------Функция шлет датчику побитно комманду command------
void send_ds18b20(unsigned char command)
{ unsigned char i, data;
data=command;
for(i=0;i<8;i++)
{
if ((data&0x01)==0x01) { // Если бит 1 - Шлем бит = 1
DDRB|=PORTB_MASK; // liniju v 0 (старт посылки)
_delay_us(2); //pause 6mks
DDRB&=~PORTB_MASK; // liniju v 1 - na vhod (шлем бит=1 и стоп посылки)
_delay_us(65); //pause 64mks
}
else { //Если бит 0 - Шлем бит 0
DDRB|=PORTB_MASK; // liniju v 0 (старт посылки и шлем бит 0)
_delay_us(60); //pause 60mks
DDRB&=~PORTB_MASK; // liniju v 1 - na vhod (стоп посылки)
_delay_us(10); //pause 10mks
}
data=data>>1; // сдвигаем посылаемый байт на бит вправо для посылки следующего бита и так все 8 бит шлем.
}
}
//---------Функция приема 2-х байт температуры от датчика
// температура хранится в 2-х байтной temperature
unsigned int receive_ds18b20(void)
{ unsigned char i;
unsigned int temperature=0;
for(i=0;i<16;i++)
{
DDRB|=PORTB_MASK; // liniju v 0 (старт приема)
_delay_us(6); //Pause 6mks
DDRB&=~PORTB_MASK; // liniju v 1 - na vhod
_delay_us(9); //Pause 9mks , т.е. на 15 мкс считываем полученный бит
if ((PINB & PORTB_MASK)==0x00) temperature&=~_BV(i); //If recived 0 // если бит 0 записываем в i-ую позицию temperature бит 0, ~_BV(i) тоже самое что ~(1<<i)
else {
temperature|=_BV(i); //If recived 1 // если бит 1 записываем в i-ую позицию temperature бит 1, _BV(i) тоже самое что (1<<i)
}
_delay_us(55); //Pause 55mks
}
return temperature; // возвращаем 2 байта температуры
}
char ASCII_high; // переменная для старшей цифры температуры для вывода на дисплей
char ASCII_low; // переменная для младшей цифры температуры для вывода на дисплей
char * decTab = "0123456789"; // массив где номеру его элемента соответсвует цифра в ASCII (это для вывода на дисплей)
// функция принимает значение value и адресса high и high записывает в
// в эти адресса код в Ascii .
// например у нас в детятичной системе 15 , для вывода на дисплей
// мы должны послать байт '1' и байт '5' во т15 - это value
// 1 - хранится по адрессу high, 5 по адрессу low
void decByte2asciiPair(char value, char * high, char * low)
{
*high = decTab[ value/10 ];
*low = decTab[ value%10 ];
}
//--------------------LCD------------------------------------------
// задержки
#define WAIT_1ms _delay_ms(1);
#define WAIT_10ms _delay_ms(10);
// Макроопределения E - PC0 , RS - PC1 , RW - PC2
#define E PC0
#define RS PC1
#define RW PC2
// - шлем комманду на дисплей
void SEND_COM(int sys_com)
{
PORTC &= ~(1<<E) & ~(1<<RW) & ~(1<<RS); //E=0,RW=0 (peredaem),RS=0(komanda)
WAIT_1ms
PORTC = (PORTC |(1<<E)) & ~(1<<RW) & ~(1<<RS); //E=1,RW=0 (peredaem),RS=0(komanda)
WAIT_1ms
PORTD = sys_com;
WAIT_1ms
PORTC &= ~(1<<E) & ~(1<<RW) & ~(1<<RS); //E=0,RW=0 (peredaem),RS=0(komanda)
WAIT_10ms // posle posilki komandi nuzno podozdat vremja i ne slat
}// шлем данные на дисплей
void SEND_DATA(int sym_com)
{
PORTC = (PORTC |(1<<RS)) & ~(1<<E) & ~(1<<RW); //E=0,RW=0 (peredaem),RS=1(dannie)
WAIT_1ms
PORTC = ( PORTC |(1<<RS)|(1<<E) ) & ~(1<<RW); //E=1,RW=0 (peredaem),RS=1(dannie)
WAIT_1ms
PORTD = sym_com;
WAIT_1ms
PORTC = (PORTC |(1<<RS)) & ~(1<<E) & ~(1<<RW); //E=0,RW=0 (peredaem),RS=1(dannie)
WAIT_10ms // posle posilki komandi nuzno podozdat vremja i ne slat
}// инициализация дисплея
void LCD_init(void)
{
SEND_COM(0b00110000);// 8 bit 1 srtroka razmer simvola 5x8
SEND_COM(0b00000001);// ustanovka 0-adres i ocistka ekrana
SEND_COM(0b00000110);//increment adressa , t.e. kazdi sled simvol v sled znakomesto zapisetsa
SEND_COM(0b00001100);// vklucit ekran
SEND_DATA('1'); // risuem nacalnie ustanovki
SEND_DATA('5');
SEND_DATA('.');
SEND_DATA('0');
SEND_COM(0b00010100);// sdvig kursora vpravo
SEND_DATA('O');
SEND_DATA('F');
SEND_DATA('F');
SEND_COM(0b00010100);// sdvig kursora vpravo
SEND_DATA('X');
SEND_DATA('X');
SEND_DATA('.');
SEND_DATA('X');
}
//--------Обработчик прерывания по таймеру T0 ----------------
volatile char button0_state=0; // переменная-флаг нажантия кнопки 0
volatile char button1_state=0; // переменная-флаг нажантия кнопки 1
ISR(TIMER0_OVF_vect)
{
static int count_buttons_reading=0; // переменная для отсчета 40-ka интревалов по 4 мс
static int count_button0_yea=0; // переменная для подсчета количесва нажатий кнопки 0 в интервале 4*40 ms
static int count_button0_no=0; // переменная для подсчета количесва отжатий кнопки 0 в интервале 4*40 ms
static int count_button1_yea=0; // переменная для подсчета количесва нажатий кнопки 1 в интервале 4*40 ms
static int count_button1_no=0; // переменная для подсчета количесва отжатий кнопки 0 в интервале 4*40 ms
count_buttons_reading++; // прошло 4 мс , подсчитываем
if ( !((PINC>>PC3)&0x01) ) // если нажата кнопка 0
count_button0_yea++; // подсчитываем нажатие
else // если отжата кнопка 0
count_button0_no++; // подсчитываем отжатие
if ( !((PINC>>PC4)&0x01) ) // тоже самое для кнопки 1
count_button1_yea++;
else
count_button1_no++;
if ( count_buttons_reading==40 ) // resenie o sostoinii prinimaetsa cerez 40*4=160ms
{
if(count_button0_yea>count_button0_no) // если по прошествию 40-ka 4-ех милисекундных интервало нажатий больше отжатий
button0_state=1; // считаем что кнопка нажата
else
button0_state=0; // в проивном случае считаем что кнопка отжата
if(count_button1_yea>count_button1_no) // аналогично для кнопки 1
button1_state=1;
else
button1_state=0;
count_buttons_reading=0; // сброс всех счетчиков для следующего цикла из 40-ка 4 мс интервалов
count_button0_yea=0;
count_button0_no=0;
count_button1_yea=0;
count_button1_no=0;
}
}
// функция настройки таймере T0 на прерывание по переполнению
void Timer0Init(unsigned char prescaller,unsigned char int_mode)
{
TCCR0=prescaller; // taimer zapuskaetsa kak tolko v TCCR0 zadadut predddelitel(CS00-CS02)
TIMSK=int_mode;// razr-zapr prerivanija zdes tolko po perepolneniju
}
//---------------Функция чтения температуры от дачтчика--------
unsigned int read_temp(void)
{
unsigned int temp;
SREG&=~(1<<7); // globalno zaprescaem prerivanija
// код который пойдет ниже нельзя прерывать так как шина 1 Wire очень чувсвительна к временным интервалам
//------------------START preobrazovanija
while(!present_ds18b20()); // zdem пока нет otveta present от датчика
send_ds18b20(0xcc); // если дождались послыаем команду тгнорирования адресса (если 1 датчик на шине то так проще просо работать)
send_ds18b20(0x44); // шлем команду на старт преоращования
_delay_ms(750); // zdem preobrazovanije не менее 750 мс
//---------CITAEM DANNIE---------
while(!present_ds18b20()); // zdem пока нет otveta present от датчика
send_ds18b20(0xcc); // если дождались послыаем команду игнорирования адресса (если 1 датчик на шине то так проще просо работать)
send_ds18b20(0xbe); // посылаем команду чтения температуры
temp = receive_ds18b20(); // читаем 2 байта
SREG|=(1<<7); // globalno opjat razrecaem prerivanija
return temp; // возвращаем 2 прочитанных байта температуры
}
#define HIGH_TEMP 300 // верхний предел температуры здесь и далее имеется ввиду формат 30.0
#define LOW_TEMP 150 // нижний предел температуры здесь и далее имеется ввиду формат 15.0
// намприер 15.5 будет 155
signed int temperatura_tek=LOW_TEMP; // по умолчанию нижний предел температуры
signed int temperatura_tek_pred=LOW_TEMP; // по умолчанию нижний предел предыдущей текущей температуры
unsigned int temperatura_ust=LOW_TEMP; // по умолчанию нижний предел температуры
int main(void)
{
char i;
unsigned int receive_temp;// temperaura ot dancika
PORTB&=~PORTB_MASK; // otklucaem vnutrennjuu podtjazku ot vhoda PB0
DDRB&=~PORTB_MASK; // poka nastraivaem na vhod liniju dannih, s ucetom vnesney podtazki tam 1
DDRC |= (1<<E) | (1<<RS) | (1<<RW); // na vihod linii upr ekranom
PORTC &= ~(1<<E) & ~(1<<RS) & ~(1<<RW); // obnuljaem
DDRC &= ~(1<<PC3) & ~(1<<PC4); // PC3 i PC4 na vhod dla knopok
PORTC |= (1<<PC3) | (1<<PC4); // na PC3 i PC4 vklucaem vnutrennie podtjazki
DDRC |= (1<<PC5) ; // PC5 na vihod dlja upravlenija optoparoy (u nas diod)
PORTC |= (1<<PC5) ; // PC5 =1 ; po sheme ten viklucen/svetodiod ne gorit
Timer0Init( (1<<CS00) | (1<<CS01),1<<TOIE0);// preriv po taymeru0 po perepolmeniju na 4 ms nastraivaem
// делитель 64, (64/4000000)*256=0.004с
SREG|=(1<<7); // globalno razrecaem prerivanija
LCD_init(); // начальная инициализация LCD
while (1) // beskonecniy cikl
{
//********************Проверяем и обрабатываем кнопку + с выводом на экран *************************
if (button0_state==1) // если нажата кнопка увеличения температуры
{
button0_state=0; // sbrasivaem , t.e. obrabotali nazatie knopki
temperatura_ust = temperatura_ust + 5;
if (temperatura_ust > HIGH_TEMP) // проверка за выход из диапазона
temperatura_ust=LOW_TEMP;
SEND_COM(0b00000010);// ustanovka v 0-j address LCD (с 0-ой позиции дисплея у нас находится эта температура)
decByte2asciiPair((char)(temperatura_ust/10),&ASCII_high,&ASCII_low); // perevodim v aski celiju cast temperaturi
// (например 15.5 , у нас 155. / это целочисленное деление, значит 155/5=15, то что надо! Значит переводим 15 в '1' и '5')
SEND_DATA(ASCII_high); // vivodim celluji cast temperatiri
SEND_DATA(ASCII_low);
decByte2asciiPair((char)(temperatura_ust%10),&ASCII_high,&ASCII_low); // perevodim v aski celiju cast temperaturi (например 15.5 , у нас 155. / - целочисленное деление, значит 155/5=15, то что надо!)
// (например 15.5 , у нас 155. % это остаток от деление, значит 155%5=5, то что надо! Значит переводим 05 в '0' и '5') SEND_COM(0b00010100);// sdvig kursora vpravo
SEND_DATA(ASCII_low); // vivodim drobniju cast temperaturi
}
//********************Проверяем и обрабатываем кнопку - с выводом на экран *************************
if (button1_state==1) // если нажата кнопка уменшения температуры {
button1_state=0; // sbrasivaem , t.e. obrabotali nazatie knopki
temperatura_ust = temperatura_ust - 5;
if (temperatura_ust < LOW_TEMP ) // проверка за выход из диапазона
temperatura_ust=HIGH_TEMP;
decByte2asciiPair((char)(temperatura_ust/10),&ASCII_high,&ASCII_low); // perevodim v aski celiju cast temperaturi
// (например 15.5 , у нас 155. / это целочисленное деление, значит 155/5=15, то что надо! Значит переводим 15 в '1' и '5')
SEND_COM(0b00000010);// ustanovka v 0-j address LCD (на -ой позиции дисплея у нас находится эта температура)
SEND_DATA(ASCII_high); // vivodim celluji cast temperatiri
SEND_DATA(ASCII_low); decByte2asciiPair((char)(temperatura_ust%10),&ASCII_high,&ASCII_low); // perevodim v aski celiju cast temperaturi (например 15.5 , у нас 155. / - целочисленное деление, значит 155/5=15, то что надо!)
// (например 15.5 , у нас 155. % это остаток от деление, значит 155%5=5, то что надо! Значит переводим 05 в '0' и '5') SEND_COM(0b00010100);// sdvig kursora vpravo
SEND_DATA(ASCII_low); // vivodim drobniju cast temperaturi
}
// запомнили предыдущую температуру
temperatura_tek_pred = temperatura_tek;
//*********** Получаем 2 байта температуры от датчика и переводим ее в нужный формат *************************
receive_temp=read_temp(); // получаем 2 байта температуры от датчика (0-ой бит =1 - 0.5, 0 - 0.0 десятая часть)
temperatura_tek = ((receive_temp>>1)*10 ); // присваеваем температуре текущей целую часть температуры от датчика переведенную в нужный нам формат,
// т.е. если например 15.5 станет 15*10 =150
if (receive_temp & 0x01) // если дробная часть 0.5 - то (т.е. 0-й бит равен 1)
temperatura_tek = temperatura_tek+5; // то 15+5 = 155 (т.е. 15.5)
//****** Выводим на экран температуру от датчика****************************
decByte2asciiPair((char)(temperatura_tek/10),&ASCII_high,&ASCII_low); // perevodim v aski celiju cast temperaturi
SEND_COM(0b00000010);// ustanovka v 0-j address LCD
for (i=0;i<9;i++)
SEND_COM(0b00010100);// sdvig kursora vpravo на - 7 позиций (с 7-й позиции у нас находится на дисплее эта температура)
SEND_DATA(ASCII_high); // vivodim celluji cast temperatiri na ekran SEND_DATA(ASCII_low);
decByte2asciiPair((char)(temperatura_tek%10),&ASCII_high,&ASCII_low);
SEND_COM(0b00010100);// sdvig kursora vpravo
SEND_DATA(ASCII_low); // vivodim drobniju cast temperaturi
//************* Сравниваем температуру текущую и требуемую c гистерезисом и принимаем решение а ключении тэна с выводдом ON - OFF на экран
if ((temperatura_tek-temperatura_tek_pred)>0)
{
// если температура растет
if ( temperatura_tek <= (temperatura_ust + GISTERESIS)) // esli neobhodimo povisat temperaturu?
{
PORTC &= ~(1<<PC5) ; // да PC5 =0 ; po sheme ten vklucen/svetodiod gorit
SEND_COM(0b00000010);// ustanovka v 0-j address LCD
for (i=0;i<5;i++)
SEND_COM(0b00010100);// sdvig kursora vpravo на - 5 позиций (с 5-й позиции у нас находится слово ON)
SEND_DATA('O');
SEND_DATA('N');
SEND_DATA(' ');
}
else
{
PORTC |= (1<<PC5) ; // нет PC5 =1 ; po sheme ten viklucen/svetodiod ne gorit SEND_COM(0b00000010);// ustanovka v 0-j address LCD
for (i=0;i<5;i++)
SEND_COM(0b00010100);// sdvig kursora vpravo на - 5 позиций (с 5-й позиции у нас находится слово OFF)
SEND_DATA('O');
SEND_DATA('F');
SEND_DATA('F');
}
}
if ((temperatura_tek-temperatura_tek_pred)<0)
{
// если температура убывает
if ( temperatura_tek > (temperatura_ust - GISTERESIS)) // esli neobhodimo ponizat temperaturu?
{
PORTC |= (1<<PC5) ; // нет PC5 =1 ; po sheme ten viklucen/svetodiod ne gorit
SEND_COM(0b00000010);// ustanovka v 0-j address LCD
for (i=0;i<5;i++)
SEND_COM(0b00010100);// sdvig kursora vpravo на - 5 позиций (с 5-й позиции у нас находится слово OFF)
SEND_DATA('O');
SEND_DATA('F');
SEND_DATA('F');
}
else
{
PORTC &= ~(1<<PC5) ; // да PC5 =0 ; po sheme ten vklucen/svetodiod gorit
SEND_COM(0b00000010);// ustanovka v 0-j address LCD
for (i=0;i<5;i++)
SEND_COM(0b00010100);// sdvig kursora vpravo на - 5 позиций (с 5-й позиции у нас находится слово ON)
SEND_DATA('O');
SEND_DATA('N');
SEND_DATA(' ');
}
}}
projectC.7z