Перейти к содержанию

kostya_unix

Members
  • Постов

    42
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные kostya_unix

  1. Всем участникам, всем оказывающим посильную помощь в изучении мной датчика DS18B20 здравствуйте.

    После вопроса  уважаемого @ARV по подсчету контрольной суммы полученного значения 9 байтов scratchpad - ОЗУ прошло ровно две недели. Все это время я старался изучить (более или менее вдумчиво) этот вопрос, найти способ расчета контрольной суммы. Так как учится, изучать приходится самостоятельно ( в моем профессиональном окружении нет любителей микроконтроллеров ( и язык C так же осваиваю самостоятельно)), то время уходит много. Так же информации в интернете мнОго по этому вопросу, но понятной для меня, оказалось очень не много.

    Но по истечению полутора недель изучения вопроса постепенно начал вникать в суть решения этого вопроса. В итоге решение оказалось не таким и сложным как казалось вначале (но это было чуть позже ). Дорога привела меня к стандартной библиотеки <util/crc16.h> в описании которой и лежит алгоритм расчета контрольных сумм. Ссылка на описание этой библиотеки http://avr-libc.narod.ru/group__util__crc.html#g37b2f691ebbd917e36e40b096f78d996

     

    Уважаемые @ARV , @Starichok (и все кто может внести конструктивную критику) прошу Вас поправить меня и указать на ошибки.

    Вот код подсчета CRC:

    #include <util/crc16.h> 
    
    uint8_t term_code[8] = {0,0,0,0,0,0,0,0};       // массив для полученного кода значения температуры(без CRC_кода)
    uint8_t crcCode = 0;                                        // переменная для хранения полученного CRC_кода
    
    uint8_t c = 0;                                                   // переменная для отображения ошибок несоответствия контрольных сумм
    
    int checkcrc()                                                 // функция подсчета значения контрольной суммы
    {
        uint8_t crc =0;
           for (uint8_t i=0; i<sizeof term_code / sizeof term_code[0]; i++)
        {
            crc = _crc_ibutton_update(crc, term_code[i]);
        }
    
            return crc;
    }

     

    Так же создал функцию, которая сравнивает полученное значение CRC и расчетное для отображения на LCD_дисплее ( для контроля ошибок) :

    void error_crc()
    {
        if (checkcrc() != crcCode)
        {
            c=c+1;  // c определена глобально
        }
        
    }

     

     Код функции _crc_ibuttin_update(): из стандартной библиотеки <util/crc16.h>

       uint8_t _crc_ibutton_update(uint8_t crc, uint8_t data)
        {
            uint8_t i;
    
            crc = crc ^ data;
            for (i = 0; i < 8; i++)
            {
                if (crc & 0x01)
                    crc = (crc >> 1) ^ 0x8C;
                else
                    crc >>= 1;
            }
            return crc;
        }

    Способ считывания значения scratchpad ОЗУ стандартный. Описан на многих сайтах. Ссылка на один из них : http://narodstream.ru/avr-urok-20-podklyuchaem-datchik-temperatury-ds18b20-chast-1/

     

    Еще раз всем спасибо.

  2. 16 часов назад, Starichok сказал:

    дело в том, что при отработке паузы с помощью _delay_ms(750) МК больше НИЧЕГО в это время делать не может. это пустая трата процессорного времени.

    точнее, МК во время отработки паузы может обрабатывать прерывания.

    можно делать такую проверку. а можно и не делать.

    например, у меня полный приборный цикл равен 1 секунде. но я точно знаю (и ты это знаешь), что 1 секунду преобразование температуры гарантированно закончится.

    поэтому я без проверки считываю новую температуру и запускаю новую конвертацию.

    что должен делать твой прибор, я не знаю. могу только сказать, что окончательное решение ты должен выбрать сам.

    вариантов тут несколько.

    1. тупо делать задержку с помощью delay.

    2. тупо сидеть в цикле и по кругу проверять на завершение конвертации. этот вариант потребует те же самые 700-750 мс бесполезной потери времени.

    3. делать, как я - 1 раз в секунду без проверки считывать новую температуру и запускать новую конвертацию.

    может, чья-то фантазия придумает еще другие способы...

     

    Понятно. Такие операции, наверное лучше всего выполнять через таймеры (освоим и это).

    Уважаемый  @Starichok  подскажите пожалуйста алгоритм работы таймер/счетчиков, в частности обработка прерываний.

    Пишется, что при срабатывании прерываний по какому нибудь событию, нормальное выполнение программы прерывается и выполняется обработка прерывания.

    Собственно вопрос: - когда происходит обработка прерывания , основной цикл программы ожидает пока не завершится обработка прерывания ?

                                            - или цикл основной программы продолжается параллельно с выполнением обработки прерывания ?

    Собственно как то так. Прошу прощения, если изложил свой вопрос не грамотно.

  3. 13 часа назад, ARV сказал:

    Фактически нужны 2 первых байта с температурой, их считываем в соответствующую переменную, а все остальные байты считываем во временную переменную с одновременным подсчётом CRC,  и более нигде их не храним. В итоге массива нет, лишних переменных тоже нет.

    Экономия смешная, я не спорю. Просто указал возможность и такого варианта.

    В даташите НЕТ таких строк, вы процитировали кривой, вводящий в заблуждение перевод даташита! На линии DQ во время преобразования будет лог.1, а вовсе не 0.

    Зато любой тайм-слот чтения будет возвращать 0, пока преобразование не завершено. Чувствует разницу? 

    То есть вы можете обойтись без паузы в 750 мс или более, если, например, каждые 50 мс будете считывать БИТ из датчика, и, как только считаете 1, это и будет сигналом о конце преобразования.

    Однако, по геморройности этот вариант намного хуже простого ожидания...

    Да. Перевод вольный, согласен. 

  4. Большое спасибо всем, кто участвует в решении моего вопроса.

    Сразу оговорюсь, что изучаю микроконтроллеры самостоятельно, не имея предварительных навыков программирования, но имея много "прыти" и желания.

    У меня вопрос возник (как во время чтения даташит_а на датчик, так и во время просмотров кодов работы с датчиком на сайтах)....

    В даташит_е есть такие строки:

    Если DS18B20 включен с внешним питанием, ведущий может контролировать конвертирование температуры (после команды [0х44]) по состоянию шины. На шине будет присутствовать логический «0» когда происходит температурное преобразование. И логическая «1», когда конвертирование выполнено.

     То есть, можно ли пренебречь паузой в _delay_ms(750); (так как по умолчанию разрядность выставлена в 12 бит) и пользоваться только проверкой завершения конвертации?

  5. 1 час назад, Starichok сказал:

    видимо, ночью я неправильно понял смысл сказанного...

    но что-то и с утра мне плохо соображается.

    если без массива, то куда будут помещены прочитанные 9 байт? в чем тут экономия?

    зы. вчера довелось быть на дне рождения. может, поэтому плохо соображается...

    Здоровья вам (после вчерашнего).

  6. 22 часа назад, ARV сказал:

    В вашем подходе много чего не так. Есть вещи несущественные, а есть принципиальные. Код не показан целиком, так что частично буду гадать.

    1. Побайтное чтение температуры настораживает: разве вы не считываете все 9 байтов scratchpad-ОЗУ датчика? Разве вы не считаете CRC этих 9-и байт?

    2. Метод станных манипуляций с байтами (сдвиги и т.п.) совершенно лишний: датчик выдает температуру в формате int16_t, т.е. 16-битное целочисленное значение в долях градуса. А вот величина доли зависит от режима работы датчика, и в 12-битном варианте составляет 1/16 градуса. То есть считанные 2 байта представляют собой обычное число int, которое надо разделить на 16, чтобы получить температуру сразу со знаком в градусах. Только делать это можно лишь в случае, если CRC всех 9 байтов встроенной блокнотной памяти корректна.

    Вы знаете, я еще не очень хорошо разбираюсь во всех командах датчика ( изучаю самостоятельно). Датчик у меня один. Я подаю команду на преобразование температуры (0x44). Собственно с этими данными и работаю. Если Вас не затруднит, подскажите пожалуйста как считать все 9 байт с датчика. Я так понимаю, что без массива тут не обойтись? Заранее благодарен.

    Привожу функцию с помощью которой общаюсь с датчиком.

     

    signed int dt_check(void)
    {
    		DS18B20_reset();  // презагружаем (сброс\присутствие) датчик.
    		  			  
    		dt_sendbyte(204); // (0xCC) (skip rom) пропускаем идентификацию, т.к. датчик один
    		dt_sendbyte(68); // (0x44) измерить температуру
    		
    		_delay_ms(750);    // такая задержка нужна для 12-ти битного ПРЕОБРАЗОВАНИЯ (это максимальная задержка)
    				
    		DS18B20_reset();   // презагружаем (сброс\присутствие) датчик. Инициализация нужна для того, что бы
    		                   // датчик понял, что ему сейчас будет послана команда.
    		
    		dt_sendbyte(204); // (0xCC) (skip rom) пропускаем идентификацию 
    		dt_sendbyte(190); // (0xBE) (convert t) отправляем команду на чтение показаний с датчика
    		
    		T_L = dt_readbyte(); // читаем младший байт регистра температуры
    		T_H = dt_readbyte(); // читаем старший байт регистра температуры
    		
    		tt = (((T_H<<8)|T_L)*10); // общий результат полученого значения (кода) с датчика
    	
    		// вывод знака при положительной и отрецательной температуре
    		    if ((T_H & 128) ==0)
    		    {
    				// положительная температура
    				znack = 32;// знак пробел при положительной температуре
    			} 
    		    else
                { // отрицательная температура
    				tt = (65536-tt); // формула расчета отрицательной температуры
    				znack = 45;// знак минус
    							
    		    }
    					
    	return tt;
    }

     

  7. Здравствуйте всем. Вчера разобрался с расчетом отрицательной температуры..... Это окажется полезным особенно начинающим в разборе этих расчетах. 

    И так..... Для начинающих (как я) формулы в примерах не всегда понятны (хотя работают на 100%), по причине несовершенного владения битовыми сдвигами.

    И что бы было более понятно и наглядно:

    T_L = dt_readbyte(); // считываем младшие 8 бит ( из 16 передаваемых датчиком значений температуры)

    T_H = dt_readbyte(): // считываем старшие 8 бит.

    для положительной температуры:   temperatura = (((T_H<<8) | T_L) / 16) ;

    для отрицательной температуры:    temperatura = ((65536 - temperatura)/16); // 65536 это максимально возможное значение 16 бит информации с датчика, и из этого                                                                                                                                                                // максимального значения мы вычитаем реальные значения датчика в промежуток времени.

    Пример: с датчика в момент времени мы получили значение (при условии, что мы определили знак температуры ( if (!((T_H & 128) ==0)); т.е. температура отрицательная)

    FECCh и если перевести в десятичное значение: 65228, тогда при этом решении (65536 - 65228) мы получаем 308 и разделив его на 16 (т.е сдвинув в право на 4 (>>4) , мы и получаем искомое значение отрицательной температуры.

    Ну вот как то так......

    Если что-то не так в моем комментарии прошу более опытных пользователей меня поправить. Думаю, что от этого выиграют все. 

  8. Всем здравствуйте. На днях вывел первые показания температуры с DS18B20 на LED_индикатор (пока правда без знака + или -). Долго шел к этому результату, не забрасывал изучение. Советовался только с вами форумчанами (больше нескем было). Спасибо большое всем кто помогал, кто участвовал в обсуждении моего вопроса.

    По возможности буду и дальше информировать о дальнейшем ходе изучения. Продолжение будет в изучении определения знака температуры., считывания ROM кода датчика( с выводом на дисплей) ну и так далее.

  9. После смены среды разработки продолжил изучение функции инициализации датчик ( формирование импульса присутствия) и некоторого исправления (уточнения) моего кода выложенного ранее . Опытным товарищам продолжение этой темы может показаться не интересным, но это может избавить начинающих от некоторых проблем или внести дополнительную ясность.

    Итак вот что узнал.....

    Т.к. все подключенные к шине устройства имеют выходы с открытым стоком,  то для формирования логической 1 на шине используется подтягивающее сопротивление (4,7 кОм)

    Для инициализации всех подключенных ведомых устройств (датчиков), м.к. сначала формирует импульс сброса, логический ноль на шине данных, не менее 480 мкс, для того что бы после формирования положительного перепада датчики смогли ответить импульсом присутствия.

    После импульса сброса от м.к. временем нарастания единицы можно пренебречь (1 мкс.) в моем коде это было ошибочно обозначено как:  _delay_us(68); //делаем задержку для "подъема" логической единицы(через сопротивление) и ожидаем сигнал присутствия датчика (датчик просаживает на 0 шину данных).

    Когда датчик определил положительный перепад (от ноля к единице), он ожидает от 15 до 60 мкс и затем формирует импульс присутствия устанавливая на шине данных логический ноль на время от 60 до 240 мкс.

    Так что импульс присутствия может начаться, самое позднее через 60 мкс от завершения импульса сброса и может закончится, самое ранее, через (15+60) = 75 мкс от завершения импульса сброса м.к.

    Для считывания импульса присутствия от датчика, выбираем среднее значение (60~70) = 68 мкс.

    Общее время импульса присутствия датчика не менее 480 мкс (68 мкс+412 мкс)  

  10. 41 минуту назад, Armenn сказал:

    Без сопротивления 4,7к что происходит?

    Здравствуйте Armenn. Спасибо за соучастие в решении моей проблемы! 

    После того как отсоединяешь сопротивление 4,7 кОм контроллер реагирует на отключение  сигнального провода датчика. Но светодиод горит тускло, точней не то что бы тускло, а с определенной (большой) частотой включается и выключается.

    НО в моих  попытках докопаться до истины, появились сдвиги. 

    Как и писал ранее, переписал код инициализации датчика в eclipse, и все заработало так как и должно. И с сопротивлением 4,7к и с "правильным" использованием _delay_us(); (asm "nop" не использовал). Вот как то так.....

    Сейчас пытаюсь понять почему в AVR_studio прошивка не работала так как надо (может быть оптимизация кода в studio имеет место быть?).

    Буду дальше изучать как DS18D20, так и протокол 1-wire.

    Еще раз спасибо большое всем, кто помогал мне.

  11. Только что, Armenn сказал:

    По скольким проводам подключаете датчик? Два или три?

    По трем проводам. Красный на плюс, черный минус, желтый передача данных (подтянут через сопротивление к питанию). Датчик в герметичном корпусе.

  12. Спасибо всем за участие.

    Вот код программы (функцию немного изменил ( для чистоты эксперимента)).

    #define F_CPU 8000000UL  // указываем частоту
    #include <avr/io.h>
    #include <util/delay.h>
    
    void set_port_led(void)
    {  
    	DDRD = 0b00000001;
    	PORTD =0b00000000;
    	
    }
    
    void DS18B20_init(void)
    { 
       	DDRC |= (1<<PC0);    // просадили шину на 0
    	PORTC &= ~(1<<PC0);
    			
    	_delay_us(490); // время просадки на 0
    		
    	
    	DDRC &= ~(1<<PC0); // 0 перевели порт на вход для приема сигнала с датчика
      	
    	//_delay_us(68); //делаем задержку для "подъема" логической еденицы(через сопротивление)
    	               //и ожидаем сигнал присутствия датчика (датчик просаживает на 0 шину
    				   //данных.
    	
    	asm volatile ("nop");
    		
    	if (!(PINC &(1<<PC0)) == 0) // если не равен нулю
    	{
          PORTD |= (1<<PD0); //красный светодиод горит (датчик отсутствует)
    	   } 
    	     else
    	       {
                 PORTD &= ~(1<<PD0); //не горит
    	           }
    		
    	_delay_us(422);
    		
    }
    
    int main(void)
    {
    	set_port_led();
    		
        while(1)
        {
    		DS18B20_init();
    					
        }
    }

     

  13. Еще раз всем здравствуйте.

    Продолжаю бороться с инициализацией DS18B20.

    Купил вчера два новых м.к. ATmega16 и ATmega8. Пробовал как один так и другой и все безрезультатно. Верней не то, что бы совсем безрезультатно (так же как описывал проблему в самом начале( при _delay_us(68); не видит датчик, а если использую asm volatile ("nop"); тогда датчик определяется)).

    Пробовал на частотах от 1 до 8 мГц. Питание подвал как от блока питания, так и непосредственно с USB_программатора.

    Осталось попробовать ECLIPSE под Linux, может, что то с AVRStudio?  Не могу никак взять в толк......

  14. В 11.08.2015 в 22:44, nvju1967 сказал:

    Остается только кварц поставить и сначала стоит прочитать.

    Купил новую ATmega8 и пока кварц не вставил, не смог прошить. До этого случая думал, что все м.к. идут в первоначальном состоянии без кварца. А вот ведь как оказалось....

  15. 7 часов назад, snn_krs сказал:

    Может быть микросекунд ?

    Да. Спасибо. Исправил (_delay_us(68);). Но пока все по прежнему. Сегодня постараюсь приобрести новый м.к и заменить. Может в порыве вдохновения подпалил подтягивающие сопротивления внутри него....

  16. Здравствуйте форумчане. При изучении датчика DS18B20 и разбора протокола 1-wire столкнулся с такой проблемой. В функции инициализации ( в частности определения присутствия  датчика на шине), при выставлении временных задержек (по даташиту: PORTC (к которому подключен вывод датчика DQ)  490 мкс импульс сброса (PORTC = 0),  переводим PORTC на вход, ожидаем 68 мкс для того, что бы шина успела подтянутся к 1 (через сопротивление 4,7 кОм, "ловим" импульс присутствия датчика, т.е. он должен "просадить" шину в ноль. И эту просадку (ноль) должна зафиксировать ранее созданная переменная для последующей обработки (присутствует датчик или нет.

    Собственно с этого вопросы и начались. Если все установлено как пишется в уроках ( потенциал сопротивления между плюсом о шиной данных датчика 4,7 кОм,  временные интервалы тайм пласта инициализации (по даташиту), то переменная не фиксирует ответ (просадку к 0) от датчика, НО если увеличить сопротивление с 4,7 кОм до 6,8 кОм и вместо ожидания 68 мкс установить ассемблеровскую вставку NOP, тогда датчик определяется (отвечает просадкой к 0) и программно датчик виден (если вывод DQ на "горячую" вынуть из макетной платы, в программе срабатывает условие if(); 

    В чем причина такого никак не могу взять в толк. Работаю в AVR_studio на C, м.к. ATmega 16, грешил на неисправность датчика, но потом купил второй такой же(предварительно проверив его на исправность в магазине).

    Буду признателен за помощь и конструктивную критику.

    PS: прошелся по все 30 страницам заголовков форума, именно про такую проблему так и не нашел.

    Это код функции инициализации:

      

    unsigned char OK_Flag;
    
    void DS18B20_init(void)
    { 
        DDRB |= (1<<PB0);    // просадили шину на 0
        PORTB &= ~(1<<PB0);
           
        _delay_ms(500);
        
        PORTB &= ~(1<<PB0);
        DDRB &= ~(1<<PB0); // 0 перевели порт на вход для приема сигнала с датчика
        
        //_delay_us(68); //делаем задержку для "подъема" логической еденицы(через сопротивление)
        
        asm volatile ("nop");
     
        OK_Flag = (PINB &(1<<PB0));
        
        _delay_us(422);
       
        return OK_Flag; //возвращаем значение переменно в программу
        
    }
    
    int main(void)
    {
        set_port_led();
    
        while(1)
        {
           DS18B20_init();
            if (!(OK_Flag == 0))
            { 
              PORTA &= ~(1<<PA0); //если датчик отвечает(исправен),зеленый свет выключен. 
            }
              else
                { 
                  PORTA |= (1<<PA0);
                }
            
        }
    }

     

×
×
  • Создать...