|
Где то давно слямзил этот код для PIC. использовал его как образец. Пример для нескольких датчиков на линии имеется. Удачи.
Спойлер*/
//---------- //#pragma jis // допускает конфигурирование не латинских символов в обработчике строк #include <htc.h> // стандартный заголовок описания #include "ds18b20.h" // //----------
//================ //Функции работы с дачиками температуры DS18B20 //================ //;Level_High: формирует высокий уровень на шине - режим чтение данных от DS18B20 void Level_HIGH (void) { DALLAS=1; // задежка для длинных линий для формирования импульса восстановления __delay_us(6); // 10мкС время подачи высокого тока для компенсации паразитной емкости линии TRISDAL=1; // настройка порта на прием данных }//----------
//================ // Level_LOW: формирует низкий уровень на шине void Level_LOW (void) { DALLAS=0; //установить низкий уровень на шине TRISDAL=0; //настройка порта на передачу данных __delay_us(1); //при 3 была ошибка }//----------
//================ // DLIT_WR: формирование паузы ожидания // задержка 60 mks, в которая необходима DS1820 для чтения или записи бита данных. void Waiting_WR (void) { __delay_us(52); //52 необходима длительность функции }//----------
//================ //crc_bits: вычисление контрольной суммы crc8 для DS18B20 char CRC_BITS (int data) { int i = (data ^ crc) & 0xff; crc = 0; if(i & 0b00000001)crc ^= 0x5e; if(i & 0b00000010)crc ^= 0xbc; if(i & 0b00000100)crc ^= 0x61; if(i & 0b00001000)crc ^= 0xc2; if(i & 0b00010000)crc ^= 0x9d; if(i & 0b00100000)crc ^= 0x23; if(i & 0b01000000)crc ^= 0x46; if(i & 0b10000000)crc ^= 0x8c; return crc; }//----------
//================ //RESET_DALLAS:формирование импульса сброса и тестирование присутствия датчика // возвращает 0 - связь с датчиком установлена // 1 - нет связи постоянно высокий уровень (обрыв) // 2 - нет связи постоянно низкий уровень (замыкание) char Reset_Dallas (void) { char ERR_LINE; // линния исправна связи датчика иcправна unsigned char a; Level_LOW(); //сформировать импульс сброса >480 mks __delay_us(700); //задержка 700 mks
// контроль импульса присутсвия, проверка состояниия линии данных ERR_LINE=0;// инициализация бита ошибки - линния исправна связи датчика иcправна di();//запретить прерывания
//tttt3: di(); // запретить прерывания // if(GIE==1)goto tttt3; // запретить прерывания
Level_HIGH(); //установить высокий уровень // __delay_us(15); //задержка 15 mks // ожидание низкого уровня импульса присутствия a=0; while (ERR_LINE==0&&DALLAS==1) { CLRWDT(); __delay_us(5); //задержка 5 mks if(++a>120)ERR_LINE=1; // нет ответа - обрыв линии данных } ei();//разрешить прерывания
// ожидание окончания импульса присутствия, ждем высокий уровень a=0; while (ERR_LINE==0&&DALLAS==0) { CLRWDT(); __delay_us(5); //задержка 5 mks if(++a>120)ERR_LINE=2; // нет ответа - замыкание линии данных } __delay_us(700); //задержка >480 mks
//задержка аварии, защита от возможных помех if(ERR_LINE>0) { error_con++;//таймер задежки аварии if(error_con<25 && TESTDT==0)ERR_LINE=0;//очистка аварии пока таймер не переполнился } else error_con=0;//очистка таймера // ERR_LINE=0;//test alarm return ERR_LINE; }//----------
//================ // Dreceive: Эта подпрограмма читает данные из DS18B20. char Dreceive (void) { char COM_REG,a; COM_REG=0; for (a=0; a<8; a++) // цикл чтение от даласса шины { // tttt0: di(); // запретить прерывания if(GIE==1)goto tttt0; // запретить прерывания Level_LOW (); // старт чтения бита установить низкий уровень) Level_HIGH (); // начать чтение COM_REG=COM_REG>>1; // сдвиг + запись в 7 разряд 0 if (DALLAS==1)COM_REG |= 0b10000000;// установка в 7 разряде 1 если DALLAS==1 ei(); // функция включить прерывания Waiting_WR(); //ожидать для окончания формирование далласом бита } return COM_REG; }//----------
//================ // Dsend: Эта подпрограмма посылает команды к DS1820. void Dsend(char COM_REG) { char a; for (a=0; a<8; a++) { tttt1: di(); // запретить прерывания if(GIE==1)goto tttt1; // запретить прерывания Level_LOW (); if(COM_REG & 0b00000001) Level_HIGH (); COM_REG=COM_REG>>1; ei(); // функция включить прерывания Waiting_WR (); Level_HIGH (); } }//----------
//================ /*celsio: функция чтение данных температуры с дачиков. Функция активирует преробразование температуры по всем датчикам, по окончании, и по адресам записанных в EEPROM производит чтение температуры. Данные сохраняются во внешнем буфере. использует информацию NACHAD - начало блока адресов в ПЗУ COLDAT - разрешенное количество датчиков возвращает // ошибки // 0; // нет ошибок опрошены все датчики // 1; // запущено конвертирование // 2; // идет конвертирование // 3; // ошибка линии данных - нет датчика или короткое на шину питания датчика // 4; // ошибка линии данных - на линии низкий уровень // 5; // ошибка линии данных */ char Celsio (void) { char a, nomdat; // внутреняя переменная цикла
const char con_dro[] = { 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, 00}; // 00.06.13.19.25.31.38.44.50.56.63.69.75.81.88.94.100 значение от дисретизации
int tempertura; static bit MINUS;
if(CONFLAG==1)// проверка ход процесса конвертирования { if(CONV==0) CONFLAG=0; else return 2; // идет конвертирование } else { a=Reset_Dallas();// формирование импульса сброса if (a==0) { Dsend (0xCC);// команда для всех устройств Dsend (0x44);// конверитирование температуры CONV=1; CONFLAG=1; return 1; //запущено конвертирование } else { if (a==1) return 3; //ошибка линии данных-нет датчика, обрыв на шине высокий уровень) else return 4; //ошибка линии данных-замыкание на чине (низкий уровень) } } // цикл чтения данных температуры со всех установленных датчиков //---------- // привод состояния всех регистров даласов для чтения, // без этой процедуры первый датчик при чтении будет // "иногда" давать ошибку CRC/ Reset_Dallas();// формирование импульса сброса Dsend (0xCC); Dsend(0xBE); Dreceive(); Dreceive(); Dreceive(); Dreceive(); Dreceive(); Dreceive(); Dreceive(); Dreceive(); Dreceive(); //---------- nomdat=0; while (1) { // проверка наличие адреса следующего датчика в ПЗУ // если первый байт == 0х28, значит датчик существует. if (EEPROM_READ((nomdat<<3)+NACHAD)!= 0x28) { coldachu=nomdat; // всего датчиков установлено break; // прервать опрос достигнуто пустое место }
if (Reset_Dallas()==0)// формирование импульса сброса с проверкой импульса присутствия датчиков { Dsend(0x55); // команда вызов датчика в соотвествии с его адресом // загрузка адреса датчика температуры с которым предстоит работать EEADR=((nomdat<<3)+NACHAD); for (a=0;a<8;a++) { RD=1; Dsend(EEDATA); EEADR++; } } else { return 5; // ошибка линии связи }
// чтение температуры и проверка crc Dsend(0xBE); // команда чтения памяти crc=0; // обнулить байт контрольной суммы tempertura=Dreceive(); // читаем байт 01 CRC_BITS(tempertura); a=Dreceive(); // читаем байт 02 tempertura+=a<<8; CRC_BITS(a); CRC_BITS(Dreceive()); // читаем байт 03 CRC_BITS(Dreceive()); // читаем байт 04 CRC_BITS(Dreceive()); // читаем байт 05 CRC_BITS(Dreceive()); // читаем байт 06 CRC_BITS(Dreceive()); // читаем байт 07 CRC_BITS(Dreceive()); // читаем байт 08 CRC_BITS(Dreceive()); // читаем байт 09
// обработка ошибки, задержка аварии защита от возможных помех if(crc!=0) // 0=обычный режим работы и количество ошибок <10 { if (erroDT[nomdat]<10) erroDT[nomdat]++; // счетчик ошибок увеличим количество ошибок
if (erroDT[nomdat]>=10||TESTDT==1) // более 10 ошибок чтения, или тестовый режим { switch (nomdat) { case 0 : ET00=1; break; case 1 : ET01=1; break; case 2 : ET02=1; break; case 3 : ET03=1; break; case 4 : ET04=1; break; case 5 : ET05=1; break; case 6 : ET06=1; break; case 7 : ET07=1; break; case 8 : ET08=1; break; case 9 : ET09=1; break; case 10 : ET10=1; break; case 11 : ET11=1; break; case 12 : ET12=1; break; case 13 : ET13=1; break; case 14 : ET14=1; break; case 15 : ET15=1; break; } } } else { erroDT[nomdat]=0; // обнулим счетчик ошибок текущего датчика switch (nomdat) { case 0 : ET00=0; break; case 1 : ET01=0; break; case 2 : ET02=0; break; case 3 : ET03=0; break; case 4 : ET04=0; break; case 5 : ET05=0; break; case 6 : ET06=0; break; case 7 : ET07=0; break; case 8 : ET08=0; break; case 9 : ET09=0; break; case 10 : ET10=0; break; case 11 : ET11=0; break; case 12 : ET12=0; break; case 13 : ET13=0; break; case 14 : ET14=0; break; case 15 : ET15=0; break; } //---------- // преобразование кода температуры датчика в двоичное чиcло MINUS=0; if (tempertura & 0x8000) { tempertura=-tempertura; // если отрицательна MINUS=1; } a=tempertura; // преобразование долей градуса a &= 0b00001111; // в десятичное значение a=con_dro[a]; // tempertura>>=4; // формирование значение температуры tempertura=(tempertura&0x00ff)*10; // например, 22,5 как tempertura=tempertura+a; // 225 if (MINUS==1) { tempertura=-tempertura; } TEMPDAT[nomdat]=tempertura; } if(++nomdat == COLDAT) { coldachu=nomdat; break; // прервать опрос все датчики опрошены } } return 0; }//----------
//================ /*seachROM: - функция поиска сетевого адреса датчика позволяет последовательно читать все адреса датчиков температуры установленные в сети. внешние переменные bayt08,bayt07,bayt06,bayt05,bayt04,bayt03,bayt02,bayt01 - текущее значение РОМ датчика chetchik_bit - счетчик который определяет какой на данный момент читается бит РОМ датчика tekuc_nesoot - регистр который хранит на каком шаге зафиксирована текущее несоответствие при чтении битов РОМ датчика posled_nesoot - счетчик который хранит число несоответствий от предыдущего чтения РОМ датчика возвращает значение 0- все адреса датчиков считаны 1- считан текущий адрес, но еще есть не считанные адреса 2- в считанном адресе ошибка crc 3- выход по аварии нет связи с ДТ 4- не корректный ответ при чтении бита данных А=В=1 (сбой шины) */ char SeachROM (void) { char chetchik_bit,tekuc_nesoot; static bit bA,bB; CLRWDT(); // сброс сторожевого таймера +++++++++++++++++++++- tekuc_nesoot=0; // сбросить маркер текущего несоответствия в ноль if (Reset_Dallas()!=0) // формировать начала обмена { return 3; // выход по аварии нет связи с ДТ }
Dsend (0xF0); // послать команду поиск ROM for (chetchik_bit=0;chetchik_bit<64;chetchik_bit++) { //прочитать 2 байта с шины tttt2: di(); // запретить прерывания if(GIE==1)goto tttt2; // запретить прерывания Level_LOW (); // старт чтения бита установить низкий уровень) Level_HIGH (); // начать чтение bA=0; if (DALLAS==1)bA=1; // Waiting_WR(); // ожидать для окончания формирование далласом бита Level_LOW (); // старт чтения бита установить низкий уровень) Level_HIGH (); // начать чтение bB=0; if (DALLAS==1)bB=1; // Waiting_WR(); // ожидать для окончания формирование далласом бита ei(); // функция включить прерывания
//проверяем биты (А) и (В) if (bA && bB) // если А=В=1 - то это ошибка { posled_nesoot=0; // очистить индикатор последнего несоответствия return 4; // не корректный ответ при чтении бита данных А=В=1 }
if(!bA && !bB) // если А=В=0 на шине присутствуют несколько датчиков { //ситуация несоответствия, алгоритм "разруливания" if (chetchik_bit==posled_nesoot) { bA=1; // установить 1 } else { if (chetchik_bit>posled_nesoot) { tekuc_nesoot=chetchik_bit; // новое текушее несоответсвие - new current mismatch bA=0; // установить 0 } else //chetchik_bit<posled_nesoot { if (bufdt[0] & 0b00000001) { bA=1; // установить 1 - set to 1 } else { tekuc_nesoot=chetchik_bit; // новое текушее несоответсвие - new current mismatch bA=0; // установить 0 - set to 0 } } } } // формирование получаемого адреса ДТ bufdt[0]>>=1; if (bufdt[1] & 0b00000001)bufdt[0] |= 0b10000000; bufdt[1]>>=1; if (bufdt[2] & 0b00000001)bufdt[1] |= 0b10000000; bufdt[2]>>=1; if (bufdt[3] & 0b00000001)bufdt[2] |= 0b10000000; bufdt[3]>>=1; if (bufdt[4] & 0b00000001)bufdt[3] |= 0b10000000; bufdt[4]>>=1; if (bufdt[5] & 0b00000001)bufdt[4] |= 0b10000000; bufdt[5]>>=1; if (bufdt[6] & 0b00000001)bufdt[5] |= 0b10000000; bufdt[6]>>=1; if (bufdt[7] & 0b00000001)bufdt[6] |= 0b10000000; bufdt[7]>>=1; if (bA==1)bufdt[7] |= 0b10000000; tttt3: di(); // запретить прерывания if(GIE==1)goto tttt3; // запретить прерывания // формирует на шине 0 или 1 в зависимости от бита (А) Level_LOW(); // строб if (bA) Level_HIGH(); // если 1 формируем единицу // else Level_LOW(); // иначе формируем ноль Waiting_WR(); // ожидания окончания Level_HIGH(); // возврат линии в 1 ei(); // функция включить прерывания // повторяем цикл 64 раза } // определить текущее несоответствие последним posled_nesoot=tekuc_nesoot; // проверка crc полученног адреса crc=0; // обнулить бйт контрольной суммы CRC_BITS(bufdt[0]); // читаем байт 01 CRC_BITS(bufdt[1]); // читаем байт 02 CRC_BITS(bufdt[2]); // читаем байт 03 CRC_BITS(bufdt[3]); // читаем байт 04 CRC_BITS(bufdt[4]); // читаем байт 05 CRC_BITS(bufdt[5]); // читаем байт 06 CRC_BITS(bufdt[6]); // читаем байт 07 CRC_BITS(bufdt[7]); // читаем байт 08 // контроль crc if (crc==0) { if (posled_nesoot == 0) { return 0; // все адреса датчиков считаны } return 1; // считан текущий адрес, но еще есть не считанные адреса } return 2; // в считанном адресе ошибка crc
}//----------
//================ /* ustdate: функция предназначена добавления или замены неисправных датчиков. Ее функция поиск свободного места и запись в ПЗУ адресов датчиков. Функция "берет" полученный адрес датчика температуры и сравнивает его с адресами хранящимися в EEPROM. Если датчик присутствует, работа прерывается, и функция возвращает 0 -датчик уже присутствует. Если в EEPROM адрес датчика не найден, функция начинает просматривать список адреса, которые помечены как неактивные. Если встречен такой адрес, то функция записывает полученный адрес на место неактивного и возвращает значение 1 - датчик "заменен". Если в EEPROM адрес датчика не найден и нет неактивных датчиков, функция проверяет наличие свободного места и при его наличии сохраняет в нем полученный адрес датчика температуры. При этом возвращает значение 2 - датчик установлен на свободное место. Если свободного места нет, функция возвращает значение 3 - нет места для установки датчика.
входные переменные NACHAD - начало блока адресов в ПЗУ COLDAT - разрешенное количество датчиков
возвращаемое значение 0 - датчик уже присутствует 1 - датчик "заменен" 2 - датчик установлен на свободное место 3 - нет места для установки датчика Длина адреса датчика 8 байт */ char SaveROM (void) { char al,nmdt,nmdt_temp; //переменная, адрес свободного места, буферный регистр static bit ERRO;
// поиск полученного адреса в ПЗУ for (nmdt=0;nmdt<COLDAT;nmdt++) // инициализация цикла поиска и сравнения кодов датчиков { // первый бит должен быть равен 0x28, если не равен место свободно if (EEPROM_READ(NACHAD+(nmdt*8)) == 0x28) { // тогда проверит три первые байты на совпадение if ((EEPROM_READ(++EEADR)==bufdt[1])&& (EEPROM_READ(++EEADR)==bufdt[2])&& (EEPROM_READ(++EEADR)==bufdt[3])) { return 0;// закончить работу функции датчик с таким адресом уже присутвует } } else { break; // найденно свободное место } }
ERRO=1; // предпологаем, что будет замена датчика nmdt_temp=nmdt; // запомним значение указателя на свободное место // поиск неисправного датчика (биты устанавливаются программой celsio) // если неисправных несколько, выбирается первый // его бит неисправности аннулируется // и адрес нового датчика будет помещен в "это место" nmdt=0; if(ET00==1)ET00=0; else { nmdt++; if(ET01==1)ET01=0; else { nmdt++; if(ET02==1)ET02=0; else { nmdt++; if(ET03==1)ET03=0; else { nmdt++; if(ET04==1)ET04=0; else { nmdt++; if(ET05==1)ET05=0; else { nmdt++; if(ET06==1)ET06=0; else { nmdt++; if(ET07==1)ET07=0; else { nmdt++; if(ET08==1)ET08=0; else { nmdt++; if(ET09==1)ET09=0; else { nmdt++; if(ET10==1)ET10=0; else { nmdt++; if(ET11==1)ET11=0; else { nmdt++; if(ET12==1)ET12=0; else { nmdt++; if(ET13==1)ET13=0; else { nmdt++; if(ET14==1)ET14=0; else { nmdt++; if(ET15==1)ET15=0; else { nmdt=nmdt_temp; // неисправных датчиков нет. ERRO=0;// установить указатель на свободное место } } } } } } } } } } } } } } } } // запись адреса датчика в ПЗУ if (nmdt_temp<nmdt)nmdt=nmdt_temp; // если найдено раньше свободное место // чем бит установленной аварии, писать в свободное
if ((nmdt<COLDAT)) { while (WR) continue; for (al=0;al<8;al++) { EEPROM_WRITE(NACHAD+(nmdt*8)+al,bufdt[al]); while (WR) continue; } // формирование ответа функции if (ERRO) return 1; // замена датчика else return 2; // датчик установлен (на первое свободное место в памяти) } else return 3; // все свободные места заняты!!
}//----------
//================ //ERASE_EEPROM: функция очищает облать хранения адресов дачиков температуры в EEPROM. void EraseROM (void) { char zec; // инициализация указателя на начало области ПЗУ адресов датчиков
while (WR) continue; for (zec=0;zec<COLDAT;zec++) { EEPROM_WRITE(NACHAD+(zec*8),0xFF); while (WR) continue; }
for (zec=0;zec<COLDAT;zec++) { TEMPDAT[zec]=0; // очистка памяти считанных температур датчиков } ET00=0; ET01=0; ET02=0; ET03=0; ET04=0; ET05=0; ET06=0; ET07=0; ET08=0; ET09=0; ET10=0; ET11=0; ET12=0; ET13=0; ET14=0; ET15=0; }//----------
//================ /*Test_DT: функция предназначена для создание цикла для поиска подключенных датчиков и записи из адресов в EEPROM памяти*/ char Test_DT (void) { // измеряем температуру по всем датчикам char a; // a=6; TESTDT=1; // бит отключения задежки тестирования ошибок do // опрос датчиков температуры { CLRWDT(); a=Celsio(); }while (!((a==0) || (a==3) || (a==4) || (a==5)));
if ((a==3) || (a==4) || (a==5)) return 1; // запись адресов в ПЗУ
naydendatch=0; // для подсчета найденных датчиков a=1; while (!((a==0) || (a==2) || (a==3) || (a==4))) { a=SeachROM(); //поиск датчика naydendatch++; //количество найденных датчиков if(a==1 || a==0) { // test=SaveROM(); //сохранение адреса датчика SaveROM(); //сохранение адреса датчика } } return 0; }//----------
_________________ ZZZ С Нами Бог ZZZ
|