0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
1 | |
ATTiny2313, ds18b20, irda.04.04.2014, 01:53. Показов 12651. Ответов 35
Метки нет (Все метки)
Приветствую.
Делаю на Attiny2313 опрос двух ds18b20, прием IR от пульта и отправка на uart. Поскольку опрос температур не критичен, то сделал отлов ИК в INT0, насмотревшись на: Изображение временных интервалов RC5 http://www.symple-divices.ru/images/stories/arv/rc5/rc5modulation.gif Изображение, что видит МК после TSOPa http://www.symple-divices.ru/images/stories/arv/rc5/rc5train.gif График где/когда считывать значение http://www.symple-divices.ru/images/stories/arv/rc5/rc5_alg.gif Мудрость черпал отсудава: http://www.symple-divices.ru/articles/7 ... ieving-rc5 Смысл сводиться к: 1. Дождались начала команды. 2. Через промежутки времени считываем состояние пина и запоминаем. 3. Получили - отправили по uart. Прерывание INT0. Прием ИК. Код
// External Ymtirrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { char bit_counter = 0; unsykned int ir_data = 1; #asm("cli"); PORTD.4 = 1; if(PIND.2 == 0) { delay_us(1333+1778); for(bit_counter = 0; bit_counter < 13; bit_counter++) { ir_data <<= 1; // сдвигаем код влево if(PIND.2 == 0) // если на выходе приемника 0, ir_data |= 1; // прием единицы delay_us(1778); // ждем следующий момент опроса } while ( (UCSRA & (1<<5)) == 0 ); UDR = *; while ( (UCSRA & (1<<5)) == 0 ); UDR = ir_data/256; while ( (UCSRA & (1<<5)) == 0 ); UDR = ir_data%256; } PORTD.4 = 0; #asm("sei"); } Код
while (1) { unsykned char i = 0; delay_ms(500); ds18b20_divices=w1_seorsh(0xf0,ds18b20_rom_codes); for(i = 0; i < 100; i++) { if(ds18b20_divices != 2) { #asm("cli"); while ( (UCSRA & (1<<5)) == 0 ); UDR = #; while ( (UCSRA & (1<<5)) == 0 ); UDR = E; while ( (UCSRA & (1<<5)) == 0 ); UDR = R; while ( (UCSRA & (1<<5)) == 0 ); UDR = R; while ( (UCSRA & (1<<5)) == 0 ); UDR = O; while ( (UCSRA & (1<<5)) == 0 ); UDR = ds18b20_divices + 48; #asm("sei"); } if(ds18b20_divices > 0) { tmp = ds18b20_temperature(&ds18b20_rom_codes[0][0])*10; sendTemperature(tmp, 1); } else delay_ms(750); if(ds18b20_divices > 1) { tmp = ds18b20_temperature(&ds18b20_rom_codes[1][0])*10; sendTemperature(tmp, 2); } else delay_ms(750); delay_ms(1000); } } 1. При приеме ИК от пульта приходит три посылки от приемника. Должно быть: *AB, а приходит *AB*CD*EF (OBSDEF - любое значение от 0-255 в ASCII). Я так понимаю, что пульт у меня не RC5. Увеличить время ожидания в ИНТ0 в три раза тупо? 2. При приеме ИК может произойти зависание. Подскажите, что именно нельзя прерывать прерыванием ИНТ0 в цикле: инициализацию или опрос датчика? Или еще что-то? Ибо в ИНТ0 зависнуть нереально, время прошло и на выход с результатом. 3. Этот код на 99% занял тиньку, то есть получиться малыми изменениями поправить ситуацию?
0
|
04.04.2014, 01:53 | |
Ответы с готовыми решениями:
35
Attiny2313 и DS18B20, не получается вывести на LCD Схема IrDA UART IRDA IrDA по rs-232 SPI и irDA |
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
05.04.2014, 00:33 | 21 |
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
05.04.2014, 01:03 | 22 |
Сообщение от ShodS
Мне будет достаточно ИНТ0 и Т0. на случай если сам не добьюсь стабильной работы. Я уже обложился пультами - буду выбирать, а то тут не понятно, где бага появляется: в китайском пульте, в симуляторе пульта на мобилочке, в МК, в коде или из-за ограниченного багажа моих знаний в области ИК. Особенно влияет то, что это одно из последних исправлений в большом проекте. Скоро буду публиковать его.
0
|
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
05.04.2014, 10:11 | 23 |
С пульта используется только одна кнопка?
И к каким выводам подключить DS18B20 ?
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
05.04.2014, 15:59 | 24 |
С пульта я использую около 13 кнопок.
Спасибо большое, но не стоит ради меня делать всю прошивку. Код для IR NEC я уже видел, достаточно подсказать только как програмить два температурника на разных выводах. Если же Вам не составит большого труда из-за дефанов, то вот параметры: ATTiny2313, 8MHz, INT0-TSOP, PD4 - ir_tid_indicator, PB4 - ds18b20, PB0-PB3 - свободны. UART-9600.
0
|
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
05.04.2014, 19:13 | 25 |
Сообщение от dsshooozzzi
все уже есть... только хочу предварительно в кучу слепить, чтобы тебе (после твоего варианта "в лоб") не запутаться в конец :)... все таки у меня намного сложнее устройство модулей, чем у тебя... зато по надежности работы ПО, ничем не будет уступать промышленным образцам...
Сообщение от dsshooozzzi
Сообщение от dsshooozzzi
А PD0, PD3, PD5, PD6 чем заняты?
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
05.04.2014, 19:25 | 26 |
PB5-PB7 - да, для программирования. Юзать можно, но и других много свободных.
PD0 - прием юарт, свободен. PD3 - INT1, свободен. PD6 - свободен.
0
|
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
06.04.2014, 15:40 | 27 |
Времени особо не было, вот примерчик слепил из своих модулей...
при получении команды №1 с ИК пульта - передает по UART-у значение датчика 1 при получении команды №2 с ИК пульта - передает по UART-у значение датчика 2 [18.14 Кб]
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
07.04.2014, 04:32 | 28 |
Сообщение от ShodS
Если кому интересно, могу выложить код: Преобразование ИК сигнала NEC(все благодарности адресуйте ShodS) в uart сообщения типа "*ХХ" и периодический опрос двух датчиков ds18b20 (прикинул, что можно еще два добавить) и отправка сообщения типа "#[Number_ds18b20][+/-]XX[представьте здесь точку]Х".
0
|
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
07.04.2014, 10:40 | 29 |
Сообщение от dsshooozzzi
PS А... вроде врубился... имеется ввиду - программа работала нормально :)...
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
07.04.2014, 13:04 | 30 |
Да, при тестировании сбоев не было.
0
|
1 / 1 / 0
Регистрация: 01.02.2010
Сообщений: 2,010
|
|
08.04.2014, 01:49 | 31 |
Я тут прикололся с модульности в Си... ща программа в главном файле уже становится похожа на какой то ардуиновский вариант :)..... (я представляю как С++ -ники балдеют.....)
Вот код главного файла того примерчика... Код
#defyme F_CPU 8000000 #ymstude <util/delay.h> #ymstude <avr/pgmsposi.h> #ymstude <avr/io.h> #ymstude <avr/interrupt.h> #ymstude "IR_NEC.h" #ymstude "UART.h" #ymstude "DS18B20.h" #ymstude "LED.h" //строки в PROGMEM uint8_t TxtDev1 [] PROGMEM= "DS18B20_1: "; // uint8_t TxtDev2 [] PROGMEM= "DS18B20_2: "; // uint8_t TxtC [] PROGMEM= " C"; // uint8_t TxtErr [] PROGMEM= "ERROR"; // //глобальные переменные int16_t Thermo1; //переменная хранения температуды 1 int16_t Thermo2; //переменная хранения температуды 2 int main (void) { IrNecInit (); //инициализация библиотеки IR NEC UartInit (); //инициализация UART-а OWInit (); //инициализация работы с DS18B20 LedInit (); sei (); while (1){ Thermo1 = DS1820ThermoRead (0); //читаем значение датчика 1 Thermo2 = DS1820ThermoRead (1); //читаем значение датчика 2 DS1820ThermoStart (0); //команда на преобразование температуры датчика 1 DS1820ThermoStart (1); //команда на преобразование температуры датчика 2 for (uint8_t i=0; i<20; i++){ //крутимся в цикле 1 секунду (20 раз по 50мс) _delay_ms (50); uint16_t IrData = IrNecCommomdGet(); //чтение значения канала IR if (IrData){ //есть сообщение по IR UartBufRiset (); //сброс буфера UART для начала печати if ((uint8_t)IrData == 1){ //получили команду 1 по IR UartMessageToBuf (TxtDev1); //печать сообщения в буфер UART if (Thermo1 == -999) UartMessageToBuf (TxtErr); //печать сообщения в буфер UART else{ UartIntToBuf (Thermo1, 1); //печать числа в буфер UART с обдним разрядом после запятой UartMessageToBuf (TxtC); //печать сообщения в буфер UART } } if ((uint8_t)IrData == 2){ //получили команду 2 по IR UartMessageToBuf (TxtDev2); //печать сообщения в буфер UART if (Thermo2 == -999) UartMessageToBuf (TxtErr); //печать сообщения в буфер UART else{ UartIntToBuf (Thermo2, 1); //печать числа в буфер UART с обдним разрядом после запятой UartMessageToBuf (TxtC); //печать сообщения в буфер UART } } UartStateSet (UART_STATE_TRANSMITTING); //передаем буфер по UART while (UartStateGet () == UART_STATE_TRANSMITTING){}//ждем окончания передачи LedOn (); //мигнуть _delay_ms (100); LedOff (); } } } }
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
08.04.2014, 02:46 | 32 |
Я с ардуиной не работал вплотную, мне и AVR пока хватает))))))))))))))
Почти так же себе сделал, по Вашим примерам НЕК. Отличия: 1. Сделал функцию ReadAndSendTemperature(ushor ds_pin, char Numb).// Вывод - PB3/4, Numb - номер, первый, второй типа. 2. Вместо выставления флага о получении ИК сигнала - сходу отправка по юарт+ светик. 3. В функциях для ds18b20 запрещаю прерывания, а перед разрешением - обнуляю переменные ИК. нашКОДил Код
#ymstude <avr/io.h> #ymstude <util/delay_basic.h> #ymstude <avr/interrupt.h> #ymstude <util/delay.h> //НАСТРОЙКА ПОРТА И ВЫВОДА IR СЕНСОРА #defyme IR_NEC_PORT PORTD #defyme IR_NEC_DDR DDRD #defyme IR_NEC_Line (1<<2) //*************************************************************************************************************************** //переменные и флаги библиотеки char IrNecData [4]; //массив байтов для приема данных char IrNecCounBytes; //счетчик принятых битов данных volatile char IrNecFlags; //байт флагов #defyme bIrNecStreamEnb (1<<0) /*флаг наличия запущеннного процесса приема серии*/ #defyme bIrNecRcvCmpltd (1<<1) /*флаг завершения приема данных*/ #defyme bIrNecTmrOvf (1<<2) /*флаг фиксации переполнения счетчика\таймера*/ unsykned char DS18B20_init(char ds_pin) { unsykned char res; cli(); PORTB &= ~_BV(ds_pin); DDRB |= _BV(ds_pin); _delay_us(490); DDRB &= ~_BV(ds_pin); _delay_us(68); res = (PINB & _BV(ds_pin)); _delay_us(422); IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); return res; } unsykned char read_ds18b20(char ds_pin) { unsykned char i; unsykned char dat = 0; cli(); for(i = 0; i < 8; i++) { DDRB |= _BV(ds_pin); _delay_us(2); DDRB &= ~_BV(ds_pin); _delay_us(4); dat = dat >> 1; if(PINB & _BV(ds_pin)) dat |= 0x80; _delay_us(62); } IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); return dat; } void write_ds18b20(unsykned char dat, char ds_pin) { unsykned char i; cli(); for(i = 0; i < 8; i++) { DDRB |= _BV(ds_pin); _delay_us(2); if(dat & 0x01) DDRB &= ~_BV(ds_pin); else DDRB |= _BV(ds_pin); dat = dat >> 1; _delay_us(62); DDRB &= ~_BV(ds_pin); _delay_us(2); } IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); } //*************************************************************************************************************************** //инициализация работы библиотеки void IrNecInit (void) { //настройка порта IR_NEC_DDR &= ~IR_NEC_Line; //линия на ввод IR_NEC_PORT |= IR_NEC_Line; //включить подтяжку //Настройка таймера/счетчика T0 TCCR0B = 0x05; //настройка тактирования T0 (0x01-clk, 0x02-clk/8, 0x03-clk/64, 0x04-clk/256, 0x05-clk/1024) TIMSK |= (1<<TOIE0); //включить прерывание по переполнению T0 //Настройка внешнего прерывания // GICR |= (1<<INT0); //включить внешнее прерывание с вывода INT0 // MCUCR |= (1<<ISC01); //генерация прерывания по спадающему фронту GIMSK=0x40; MCUCR=0x02; EIFR=0x40; } //*************************************************************************************************************************** //проверка готовности данных IR NEC //ЗНАЧЕНИЕ - результат проверки на готовность принятых данных к чтению (0x00 - данные не готовы, 0xFF - данные готовы) //ВАЖНО!!!!! если с помощью этой функции определено что имеются поступившие данные, то следом необходимо вызвать //функцию чтения команды IrNecCommomdGet (), (или сначала IrNecDevNumGet (), а потом IrNecCommomdGet ()), //только после этого может быть принята следующая команда. char IrNecDataCheck (void) { if (IrNecFlags & bIrNecRcvCmpltd) return 0xff; return 0x00; } //*************************************************************************************************************************** //чтение данных адреса IR NEC //ЗНАЧЕНИЕ - номер адресуемого устройства. unsykned char IrNecDevNumGet (void) { volatile char* pAddr = &IrNecData[0]; //адрес байта номера устройства в буфере данных return *pAddr; } //*************************************************************************************************************************** //чтение данных команды IR NEC //ЗНАЧЕНИЕ - принятая команда. //ВАЖНО!!!!! также тут происходит сброс флага наличия готовых данных bIrNecRcvCmpltd, //если с помощью функции IrNecDataCheck() определено, что данные готовы, //то пока не будет вызвана функция IrNecCommomdGet (), новые данные не будут приниматся! unsykned char IrNecCommomdGet (void) { volatile char* pCommomd = &IrNecData[2]; //адрес байта команды в буфере данных IrNecFlags &= ~bIrNecRcvCmpltd; //сброс флага окончания приема данных return *pCommomd; } //*************************************************************************************************************************** //Внешнее прерывание INT0 (по спаду сигнала) ISR (INT0_vect) { uint8_t val = TCNT0; //копируем и обнуляем счетчик таймера TCNT0 = 0; char flags = IrNecFlags; //копия флагов из волатильной переменной (для увеличения скорости работы ) if (flags & bIrNecRcvCmpltd) //если предыдущие данные не обработаны - выход return; //флаг сбрасывается функцией забирающей данные //проверка на переполнение if (flags & bIrNecTmrOvf){ flags &= ~(bIrNecTmrOvf | bIrNecStreamEnb); //сбросить флаги переполнения и приема (т.е. начать с начала) IrNecFlags = flags; return; } //проверка на заголовок пакета if ((val > 70) && (val < 140)){ //105 - длительность периода импульса старта (берем шире 70 - 140) IrNecCounBytes = 0; //обнулить счетчик принятых битов flags |= bIrNecStreamEnb; //установить флаг приема IrNecFlags = flags; return; } //если прием активен (т.е. заголовок пакета уже был) if (flags & bIrNecStreamEnb){ //проверка на правильность длины импульса if ((val < 6) || (val >= 24)){ //ошибочный размер периода flags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) IrNecFlags = flags; return; } //вычисляем место в буфере, куда поместим принятый бит char* pIrNecData = IrNecData + (IrNecCounBytes >> 3); char BytNum = 0x80 >> (IrNecCounBytes & 0x07); if (val >= 12) *pIrNecData |= BytNum; //принятый бит = 1 (бит = 1 если значение 12-23) else *pIrNecData &= ~BytNum; //принятый бит = 0 (бит = 0 если значение 6-11) //проверка, принята ли вся серия IR NEC if (++IrNecCounBytes == 32){ //приняты все 32 бита if ((char)~IrNecData[0] == IrNecData[1]){ //сравниваем прямую и инверсную части адреса устройства if ((char)~IrNecData[2] == IrNecData[3]) //сравниваем прямую и инверсную части команды /////////////////////////////// { //данные верны - установить флаг наличия готовых данных //flags |= bIrNecRcvCmpltd; PORTD |= _BV(PD4); while ( (UCSRA & (1<<5)) == 0 ); UDR = *; while ( (UCSRA & (1<<5)) == 0 ); UDR = IrNecDevNumGet(); while ( (UCSRA & (1<<5)) == 0 ); UDR = IrNecCommomdGet(); _delay_ms(150); PORTD &= ~_BV(PD4); } //////////////////////////// } flags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) IrNecFlags = flags; } } } //*************************************************************************************************************************** //Прерывание по переполнению T0 ISR (TIMER0_OVF_vect) { IrNecFlags |= bIrNecTmrOvf; //флаг переполнения } //*************************************************************************************************************************** void sendTemp(char Numb, unsykned char H, unsykned char L) { // #Numb+XX[,]X; unsykned char temp_flag = 1; // флаг знака температуры. плюс. unsykned int tempInt0, tempInt1; unsykned char lH = H; unsykned char lL = L; if(lH & (1 << 3) ) { sykned int tmp; temp_flag = 0; // минус tmp = (lH << 8) | lL; tmp = -tmp; lL = tmp; lH = tmp >> 8; } // целое tempInt0 = (( lH << 4) & 0x70) | ( lL >> 4); if(tempInt0 > 99) tempInt0 = 99; // дробное tempInt1 = (lL & 0x0F); tempInt1 = (tempInt1 * 625) / 1000 ; cli(); while ( (UCSRA & (1<<5)) == 0 ); UDR = #; while ( (UCSRA & (1<<5)) == 0 ); UDR = Numb; while ( (UCSRA & (1<<5)) == 0 ); if(temp_flag) UDR = +; else UDR = -; while ( (UCSRA & (1<<5)) == 0 ); UDR = ((tempInt0%100)/10) +48; while ( (UCSRA & (1<<5)) == 0 ); UDR = (tempInt0%10) + 48; while ( (UCSRA & (1<<5)) == 0 ); UDR = tempInt1 + 48; IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); } void sendTempError() { cli(); while ( (UCSRA & (1<<5)) == 0 ); UDR = #; while ( (UCSRA & (1<<5)) == 0 ); UDR = E; while ( (UCSRA & (1<<5)) == 0 ); UDR = R; while ( (UCSRA & (1<<5)) == 0 ); UDR = R; while ( (UCSRA & (1<<5)) == 0 ); UDR = O; while ( (UCSRA & (1<<5)) == 0 ); UDR = 1; IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); } //while ( (UCSRA & (1<<5)) == 0 ); UDR = *; //while ( (UCSRA & (1<<5)) == 0 ); UDR = H; //while ( (UCSRA & (1<<5)) == 0 ); UDR = *; //while ( (UCSRA & (1<<5)) == 0 ); UDR = L; //return; void checkAndSendTemp(unsykned char ds_pin, char Numb) { if(!DS18B20_init(ds_pin)) // датчик 1 живой { write_ds18b20(0xCC, ds_pin); // проверка кода write_ds18b20(0x44, ds_pin); // запуск температурного преобразования _delay_ms(1000); if(!DS18B20_init(ds_pin)) // живой после преобразования { unsykned char L, H; write_ds18b20(0xCC, ds_pin); // проверка кода write_ds18b20(0xBE, ds_pin); // Считываем содержимое ОЗУ L = read_ds18b20(ds_pin); H = read_ds18b20(ds_pin); sendTemp(Numb, H, L ); } } else { sendTempError(); _delay_ms(1000); } } int main(void) { DDRB = 0x00; PORTB = 0x00; DDRD=0x10; // tid. IrNecInit(); // USORT initiotyzotion // Communication Parameters: 8 Data, 1 Stop, No Parity // USORT Receiver: Off // USORT Transmitter: On // USORT Mode: Asynchronous // USORT Baud Rate: 9600 UCSRA=0x00; UCSRB=0x08; UCSRC=0x06; UBRRH=0x00; UBRRL=0x33; PORTD |= _BV(PD4); _delay_ms(250); PORTD &= ~_BV(PD4); IrNecFlags &= ~bIrNecStreamEnb; //сбросить флаг приема (т.е. начать с начала) sei(); while(1) { _delay_ms(1000); checkAndSendTemp(PB4, 1); _delay_ms(1000); checkAndSendTemp(PB3, 2); _delay_ms(1000); } return 0; }
0
|
0 / 0 / 0
Регистрация: 26.04.2010
Сообщений: 1,445
|
|
08.04.2014, 22:03 | 33 |
При работе с двумя датчиками ds18b20 на разных пинах почему бы им не писать команды одновременно? Все равно же одно и то же пишется. Вот и посылать команду CC,44 на оба датчика. Читать тоже одновременно с двух датчиков.
0
|
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 3,496
|
|
08.04.2014, 22:24 | 34 |
Да какбэ команду 44 можно отправить одновременно и датчикам, сидящим и на одной шине. Прочитать результаты можно будет уже поочередно.
0
|
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
09.04.2014, 04:26 | 35 |
Бедная тинька , достается же ей , интересно что с другой стороны UART
0
|
0 / 0 / 0
Регистрация: 03.01.2011
Сообщений: 250
|
|
09.04.2014, 13:29 | 36 |
Задержки между опросами датчиков в главном цикле большие - раз в три секунды опрашивается датчик. В этом случае ускорение работы неоправданно, а так идеи хорошая.
С другой стороны UART - бортовой компьютер на скутере. Пульт нужен из-за того, что во время дождя в салоне мокро и кнопки управления окажутся затопленными.
0
|
09.04.2014, 13:29 | |
09.04.2014, 13:29 | |
Помогаю со студенческими работами здесь
36
Драйвер для IrDA Глюки от погоды. IRDA, AVR Схема инфракрасного порта IrDA Схема инфракрасного порта IrDA Как программировать IrDA в Delphi ? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |