Реклама ⓘ
Главная » Микроконтроллеры
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

mikroPascal for AVR. Урок 6. Снова работа с OneWire. Расширенная библиотека

В речь зашла об использовании в mikroPascal (далее mP) 1-wire библиотеки. К сожалению, ребята из микроэлектроники не очень ответственно отнеслись к написанию этой библиотеки, в результате чего она получилась с небольшим функционалом. Покопавшись по интернету и почитав о шине 1-wire, решил восполнить этот пробел, и написать библиотеку для mP, где есть все необходимые функции. Мне это удалось лишь процентов на 80-90. Почему именно так, поясню позже.

Итак, приступим! 

Ниже представлен код библиотеки:

//////////////////////////////////////////////////////////////////////////////////////
//  Данная библиотека частично портирована, частично дописана мной.                 //
//  Я - это Евгений Ресин.                                                           //
//  Автор части исходного варианта на C: Погребняк Дмитрий ( http://alexrul.ru ),   //
//  за все остальное спасибо гуглу и яндексу :)                                     //
//  OwLibCust.mpas - v1.0                                                           //
//  http://cxem.net                                                                 //
//////////////////////////////////////////////////////////////////////////////////////
unit OwLibCust;

procedure OwLow(pin: byte);
procedure OwHight(pin: byte);
procedure OwWriteBit(pin, a: byte);
function OwReadBit(pin: byte): byte;
function OwReset(pin: byte): boolean;
function OwRead(pin: byte): byte;
procedure OwWrite(pin, a: byte);
procedure OwCRC(var crc: byte);
function OwTempRead(pin: byte; var temp: string[6]): boolean;
function OwGetROM(pin: byte;var rom: array [0..7] of byte): boolean;
function OwMachROM(pin: byte; var rom: array [0..7] of byte): boolean;
function OwSearch(pin: byte; var n: byte; var ROM_NO: array [0..7] of array [0..7] of byte): boolean;

implementation

var ow_bit: byte at PORTB;
    ow_ddr: byte at DDRB;
    ow_pin: byte at PINB;
//////////////////////////////////
    rom_code: array [0..7] of byte;
    crc: byte;

//////////////////////////////////////////////////////////////////////////////// Основа всей библиотеки - работа с пинами.
procedure OwLow(pin: byte);                                                   // Устанавливаем низкий уровень на линии
begin                                                                         //
     ow_bit.(pin) := 0;                                                       //
     ow_ddr.(pin) := 1;                                                       //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
procedure OwHight(pin: byte);                                                 // И высокий уровень.
begin                                                                         //
     ow_bit.(pin) := 0;                                                       //
     ow_ddr.(pin) := 0;                                                       //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
procedure OwWriteBit(pin, a: byte);                                           // Отправка на бита.
begin                                                                         //
     asm cli end;                                                             //На всякий случай отключаем прерывания
     if a = 0 then begin                                                      //И отправляем на линию "0" или "1"
        OwLow(pin);                                                           //
        delay_us(90);                                                         //
        OwHight(pin);                                                         //
        delay_us(5);                                                          //
     end else begin                                                           //
        OwLow(pin);                                                           //
        delay_us(5);                                                          //
        OwHight(pin);                                                         //
        delay_us(90);                                                         //
     end;                                                                     //
     asm sei end;                                                             //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwReadBit(pin: byte): byte;                                          //Для приема бита нам нужно
begin                                                                         //отключить прерывания, сформировать тайм - слот чтения и
     asm cli end;                                                             //проверить уровень на интересующей нас ножке микроконтроллера
     OwLow(pin);                                                              //Возвращаемое знаечение - байт
     delay_us(2);                                                             //
     OwHight(pin);                                                            //
     delay_us(10);                                                            //
     if ow_pin.(pin) = 0 then                                                 //
        result := 0                                                           //
     else                                                                     //
         result := 1;                                                         //
     delay_us(80);                                                            //
     asm sei end;                                                             //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwReset(pin: byte): boolean;                                         //Как понятно из названия, эта функция
var i: byte;                                                                  //позволяет послать импульс сброса на шину.
begin                                                                         //Возвращает true, false.
     OwLow(pin);                                                              //Соответственно, если false, то ошибка сброса
     delay_us(640);                                                           //(нет устройств и т.д.).
     OwHight(pin);                                                            //
     if ow_pin.(pin) = 1 then begin                                           //
        delay_us(2);                                                          //
        result := 0;                                                          //
        for i := 0 to 255 do begin                                            //
            if ow_pin.(pin) = 0 then begin                                    //
               result := true;                                                //
               break;                                                         //
            end;                                                              //
            delay_us(1);                                                      //
        end;                                                                  //
     end                                                                      //
     else                                                                     //
         result := false;                                                     //
     delay_us(500);                                                           //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwRead(pin: byte): byte;                                             //Чтение байта.
var i, r: byte;                                                               //
begin                                                                         //
     r := 0;                                                                  //
     for i := 0 to 7 do begin                                                 //
         r := r shr 1;                                                        //Сдвигаем биты на 1 вправо.
         if OwReadBit(pin) = 1 then                                           //Если читаемый бит = 1, то записываем.
            r := r or 0x80;                                                   //
     end;                                                                     //
     result := r;                                                             //Возвращаем полученный байт.
     delay_us(500);                                                           //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
procedure OwWrite(pin, a: byte);                                              //Запись байта.
var i: byte;                                                                  //
begin                                                                         //
     for i := 0 to 7 do begin                                                 //
         if (a shl 7) <> 0 then                                               //Для проверки, сдвигаем биты в байте, который
            OwWriteBit(pin, 1)                                                //нам нужно передать, влево на 7 бит
         else                                                                 //Если оставшийся бит = 0 то пишет 0, если
             OwWriteBit(pin, 0);                                              //же 1, то пишем 1. Далее, сдвигаем биты на 1 вправо.
         a := a shr 1;                                                        //
     end;                                                                     //
     delay_us(500);                                                           //
end;                                                                          //
                                                                              //
////////////////////////////////////////////////////////////////////////////////
procedure OwCRC(var crc: byte);                                               //Функция, с помощью которой можно проверить                                                                //CRC (циклический избыточный код).
const                                                                         //
   table : array[0..255] of byte = (                                          //Если возвращает "0" - значит данные приняты верно,
    0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,   //а если что-либо другое, то ошибка.
    157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,   //В данном варианте значение просто берется из таблицы,
    35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,   //но можно так же реализовать и расчет по формуле (в интернете есть примеры).
    190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,   //Но табличный вариант имеет преимущество в скорости выполнения.
    70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,  //
    219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,  //
    101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,  //
    248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,  //
    140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147,205,  //
    17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80, //
    175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, //
    50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, //
    202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,  //
    87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,  //
    233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, //
    116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53);
    var n: byte;                                                              //
begin
     if n < 8 then begin                                                                         //
        crc := table[CRC xor X];
        inc(n);
     end else
        n := 0;                                                                     //                                                              //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwGetROM(pin: byte; var rom: array [0..7] of byte): boolean;         //Функция для чтения одного ROM кода
var i: byte;                                                                  //(если на линии всего 1 датчик).
begin                                                                         //Возвращаемое значение - true, false;
     if OwReset(pin) then begin                                               //Если true, то можно считывать код из переменной "rom",
          OwWrite(pin, 0x33);                                                 //а если false - то ошибка (при выполнении reset).
          for i := 0 to 7 do begin                                            //
              rom[i] := OwRead(pin);                                          //
          end;                                                                //
          result := true;                                                     //
     end                                                                      //
     else                                                                     //
         result := false;                                                     //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwMachROM(pin: byte; var rom: array [0..7] of byte): boolean;        //Отправка адреса ROM. Применяется
var i: byte;                                                                  //для обращения в конкретному устройству,
begin                                                                         //если на линии их несколько.
     if OwReset(pin) then begin                                               //
        OwWrite(pin, 0x55);                                                   //
        for i := 0 to 7 do                                                    //
            OwWrite(pin, rom[i]);                                             //
        result := true;                                                       //
     end                                                                      //
     else                                                                     //
         result := false;                                                     //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwTempRead(pin: byte; var temp: string [6]): boolean;                //Из названия можно понять,
var a, b, i, k, l, d: byte;                                                   //что функция предназначена только для
    c: integer;                                                               //датчика DS18B20(максимальное разрешение - 12 бит).
begin                                                                         //
     if OwReset(pin) then begin                                               //
        OwWrite(pin, 0xCC);                                                   //
        OwWrite(pin, 0x44);                                                   //
        delay_ms(750);                                                        //
        OwReset(pin);                                                         //
        OwWrite(pin, 0xCC);                                                   //
        OwWrite(pin, 0xBE);                                                   //
        crc := 0;                                                             //
        a := OwRead(pin);                                                     //
        b := OwRead(pin);                                                     //
        ////////////////////////////////////////////////////////////////////////
        l := a;                                                               //Вот собственно процедура
        d := b;                                                               //проверки crc. Если данные
        OwCRC(l);                                                             //пришли без искажений, то
        OwCRC(d);                                                             //переменная crc после 8 ми
        for i := 0 to 6 do begin                                              //принятых байт должна быть
            k := OwRead(pin);                                                 //равна 0.
            OwCRC(k);                                                         //
        end;                                                                  //
        ////////////////////////////////////////////////////////////////////////
        if crc = 0 then begin                                                 //
           result := true;                                                    //
           c := ((b shl 8) + a) shr 4;                                        //
           if c > 1000 then c := -(4096 - c);                                 //
           IntToStr(c, temp);                                                 //
         end else begin                                                       //
             result := false;                                                 //
             exit;                                                            //
         end                                                                  //
     end                                                                      //
     else                                                                     //
         result := false;                                                     //
end;                                                                          //
////////////////////////////////////////////////////////////////////////////////
function OwSearch(pin: byte; var n: byte; var rom_no: array [0..7] of array [0..7] of byte): boolean;
var last_pos, new_pos: byte;                                                  //
    id_bit, cmp_bit, wr_var: byte;                                            //На данный момент эта функция еще на стадии доработки, так
    count, i, dat, a: byte;                                                   //как может обнаружить лишь два датчика на линии. Постараюсь
    t_dat: array [1..64] of byte;                                             //доработать эту функцию по возможности.
begin                                                                         //Моих знаний с/cpp оказалось недостаточно, что бы перевести на паскаль
     n := 0;                                                                  //процедуру, описаннцю в аппноте от maxim.
     count := 0;                                                              //
     repeat                                                                   //
     a := 0;                                                                  //
     new_pos := 0;                                                            //
     if OwReset(pin) then begin                                               //Если сброс удался, то продолжаем
        result := true;                                                       //Если же нет, то возвращаем false и выходим из функции.
        OwWrite(pin, 0xF0);                                                   //Посылаем команду "Search ROM"
        for i := 1 to 64 do begin                                             //Цикл, в котором мы перебираем все 64 бита ROM.
            id_bit := OwReadBit(pin);                                         //Читаем биты (основной и инвертированный)
            cmp_bit := OwReadBit(pin);                                        //
            if (id_bit = 1) and (cmp_bit = 1) then begin                      //Если и то, и другое = 1, то false и выход.
               result := false;                                               //
               exit;                                                          //
            end else if (id_bit = 0) and (cmp_bit = 0) then begin             //Если же спорная ситуация, то проверяем,
                if (i = last_pos) then                                        //если уже на этом месте были,
                   wr_var := 1                                                //то пишем "1", если нет - "0" и запоминаем место в new_pos.
                else if (i > last_pos) then begin                             //
                     wr_var := 0;                                             //
                     new_pos := i;                                            //
                end;                                                          //
            end else                                                          //
                wr_var := id_bit;                                             //Если же конфликтой ситуации нет, то просто запомиинаем первый приняты бит.
            t_dat[i] := wr_var;                                               //Записываем значение бита во "временный" массив.
            OwWriteBit(pin, wr_var);                                          //Посылаем бит.
            ////////////////////////////////////////////////////////////////////
            dat := dat shr 1;                                                 //Далее операция получения байта серийного номера.
            if wr_var = 1 then                                                //
               dat := dat or 0x80;                                            //
            if count = 7 then begin                                           //
               rom_no[n][a] := dat;                                           //
               count := 0;                                                    //
               inc(a);                                                        //
            end else                                                          //
                inc(count);                                                   //
        end;                                                                  //
        last_pos := new_pos;                                                  //Тут переписываем new_pos в last_pos (потом new_pos обнулим).
        inc(n);                                                               //Увеличиваем на 1 количество уст-в.
     end else begin                                                           //
         result := false;                                                     //
         exit;                                                                //
     end;                                                                     //
     until new_pos = 0;                                                       //Если new_pos = 0 (когда уже не осталось конфликтов), выходим из цикла.
end;                                                                          //
                                                                              //
end.                                                                          //

Вот такой вот unit. Код на мой взгляд не плохо прокомментирован, так что на нем особо останавливаться не буду, за исключением одного. Это одно - собственно почему :"...лишь процентов на 80-90.". Проблема в том, что мои знания в С очень и очень скромны (ну не могу на него перестроиться :) ). И исходя из этого, портировать алгоритм поиска ROM с С не вышло, точнее вышло но криво, да так, что включать в библиотеку не решился. По этому пока что ограничился двумя датчиками на 1 линии. Но, работы по разбору сишного алгоритма я не забросил, и постараюсь побыстрее выложить окончательную версию.

Но, это так, о птичках, а теперь о применении и преимуществах этой библиотеки. Главное преимущество - возможность отправлять и принимать отдельные биты. Это позволяет производить такие операции как: чтение ROM кода устройств (если их несколько, пресловутый Search ROM), а так же проводить проверку CRC. Последнее тоже далеко не последняя (по значению) функция, когда линия связи находится в условиях сильных помех (магнитные поля, некачественный кабель, большая длинна линии и т.д.). Так же, кроме этих функций, включил в библиотеку еще одну специализированную функцию - OwTempRead. Она возвращает строковую переменную со значением температуры (целое значение, но при желании можно модифицировать, и будет возвращать с точностью до десятых или сотых долей градуса).

Функции: отправка/прием бита, отправка/прием байта, чтение ROM 1 датчика, чтение ROM 2-х датчиков на линии, отправка ROM для обращения к конкретному датчику, проверка CRC, чтение температуры DS18B20 (реализована как готовая функция).

1. Чтение температуры с 1-го датчика. В принципе, тут и делать то нечего:

program CRC_verify;

uses OwLibCust;

var LCD_RS : sbit at PORTC0_bit;
var LCD_EN : sbit at PORTC1_bit;
var LCD_D4 : sbit at PORTC2_bit;
var LCD_D5 : sbit at PORTC3_bit;
var LCD_D6 : sbit at PORTC4_bit;
var LCD_D7 : sbit at PORTC5_bit;

var LCD_RS_Direction : sbit at DDC0_bit;
var LCD_EN_Direction : sbit at DDC1_bit;
var LCD_D4_Direction : sbit at DDC2_bit;
var LCD_D5_Direction : sbit at DDC3_bit;
var LCD_D6_Direction : sbit at DDC4_bit;
var LCD_D7_Direction : sbit at DDC5_bit;

var temp: string [6];
    crc, i: byte;

begin
     lcd_init;
     lcd_cmd(_LCD_CURSOR_OFF);
     While TRUE do begin
           if OwTempRead(0, temp) then
              lcd_out(1, 1, 'Temp:' + temp)
           else
               lcd_out(1, 1, 'Device 404');
           delay_ms(1000);
           lcd_cmd(_LCD_CLEAR);
     end;
end.

И скрин результата:

2. Проверка CRC. Это я позже добавил в функцию считывания температуры. Таким образом, при чтении температуры с помощью функции OwTempRead, автоматически будет проверяться CRC. При неверном CRC будет возвращено false. 

Так как код тут будет аналогичен предыдущему, то не вижу смысла его приводить. Ну а скриншот с результатом ниже (обратите внимание на окно слева (на обмен байтами)).

.

Для проверки CRC необходимо считать все 9 байт.

3. Определение серийного номера одного датчика.

program OwLib_Read1ROM;

uses OwLibCust;

var LCD_RS : sbit at PORTC0_bit;
var LCD_EN : sbit at PORTC1_bit;
var LCD_D4 : sbit at PORTC2_bit;
var LCD_D5 : sbit at PORTC3_bit;
var LCD_D6 : sbit at PORTC4_bit;
var LCD_D7 : sbit at PORTC5_bit;

var LCD_RS_Direction : sbit at DDC0_bit;
var LCD_EN_Direction : sbit at DDC1_bit;
var LCD_D4_Direction : sbit at DDC2_bit;
var LCD_D5_Direction : sbit at DDC3_bit;
var LCD_D6_Direction : sbit at DDC4_bit;
var LCD_D7_Direction : sbit at DDC5_bit;

var rom: array [0..7] of byte;                                                  //Переменная для вывода ROM кода
    i: byte;
    s: string [6];

begin
     uart1_init(9600);
     lcd_init;
     lcd_cmd(_LCD_CURSOR_OFF);
     While TRUE do begin
           if OwGetROM(0, rom) then begin                                       //Если прочитано успешно, то выполняем...
              lcd_out(1, 1, 'Read complete!');
              delay_ms(750);
              lcd_out(1, 1, 'Print...      ');
              uart_write_text('ROM:');
              for i := 0 to 7 do begin                                          //Отправляем побайтно код
                  IntToStr(rom[i], s);
                  if i < 7 then
                     uart_write_text(s + ':')
                  else
                     uart_write_text(s);
              end;
              uart_write(13);                                                   //Символ конца строки
           end else begin
               lcd_out(1, 1, 'ERROR!');                                         //Если не считалось...
           end;
           delay_ms(1000);
           lcd_cmd(_LCD_CLEAR);
     end;
end.

И результат:

В эту функцию проверку CRC я не интегрировал, но если вам это будет необходимо, то по примеру считывания температуры можете сделать это сами.

4. Считывание ROM кодов 2-х устройств на одной линии.

program OwLibCustom;

uses OwLibCust;

var LCD_RS : sbit at PORTC0_bit;
var LCD_EN : sbit at PORTC1_bit;
var LCD_D4 : sbit at PORTC2_bit;
var LCD_D5 : sbit at PORTC3_bit;
var LCD_D6 : sbit at PORTC4_bit;
var LCD_D7 : sbit at PORTC5_bit;

var LCD_RS_Direction : sbit at DDC0_bit;
var LCD_EN_Direction : sbit at DDC1_bit;
var LCD_D4_Direction : sbit at DDC2_bit;
var LCD_D5_Direction : sbit at DDC3_bit;
var LCD_D6_Direction : sbit at DDC4_bit;
var LCD_D7_Direction : sbit at DDC5_bit;

var rom: array [0..7] of byte;
    rom_all: array [0..7] of array [0..7] of byte;
    n, i, c, pos, save: byte;
    lstdev: boolean;
    s : string [6];

begin
     uart1_init(9600);
     lcd_init;
     lcd_cmd(_LCD_CURSOR_OFF);
     while true do begin
           uart_write_text('Ready...');
           uart_write(13);
           delay_ms(1000);
           lcd_cmd(_LCD_CLEAR);
           if OwSearch(4, n, rom_all) then begin
              IntToStr(n, s);
              lcd_out(1, 1, 'Device:' + s);
              for i := 0 to n - 1 do begin
                  uart_write_text('ROM:');
                  for c := 0 to 7 do begin
                      IntToStr(rom_all[i][c], s);
                      if c < 7 then 
                         uart_write_text(s + ':')
                      else begin
                          uart_write_text(s);
                          uart_write(13);
                      end;
                  end;
              end;
           end else
               lcd_out(1, 1, 'Device 404');
           delay_ms(1000);
     end;
end.

Как и в предыдущем примере, для вывода ROM адресов был использован UART.

Что вышло, смотрите ниже:

Вот и конец этого урока. Спасибо всем тем, кто смог дочитать до конца! 

Прикрепленные файлы:

Теги:

Опубликована: Изменена: 09.12.2014 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (0) | Я собрал (0) | Подписаться

Статью еще никто не комментировал. Вы можете стать первым.
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Программатор Pickit3
Программатор Pickit3
Набор начинающего радиолюбителя Осциллограф DSO138
вверх