Главная » Микроконтроллеры
Призовой фонд
на октябрь 2017 г.
1. Термометр Relsib WT51
Рэлсиб
2. 1000 руб
PCBWay
3. Регулируемый паяльник 60 Вт
Паяльник
4. 100 руб.
От пользователей

mikroPascal for AVR. Урок 3. Еще раз UART а также немного о прерываниях

Ну вот, после очень большого перерыва я наконец что-то смог сделать. Эта третья по счету статья о среде программирования mikroPascal, речь в которой пойдет снова о UART. 
Первая статья, вторая статья

В этот раз все будем делать наглядно. В качестве "экспоната" я решил использовать исходник программы "iCPU". Вообще то в связке должны работать две программы: на ПК и на микроконтроллере. Так как выбор пал на микроконтроллер Atmega8, то связь с ПК будет через COM порт (виртуальный). Под словом "связь" имеется ввиду прием данных. Но на данный момент, в программа под Windows не готова, и будем использовать моделирование в Proteus + терминал.

Итак, еще раз о UART:

UARTx_Init(baud_rate : dword); //Инициализация 1 UART модуля (для тех МК, где их несколько)
UARTx_Init_Advanced(baud_rate : dword; parity : byte; stop_bits : byte); //Расширенная инициализация UART. Можно задать параметры: бауд рейт, четность, стоповые биты.
UARTx_Data_Ready(): byte; //Возвращает "1" если в буфере приема есть данные.
UARTx_Tx_Idle(): byte; //Возвращает "1" если данные были переданы.
UARTx_Read(): byte; //Процедура считывания данных;
UARTx_Read_Text(var Output : string[255]; var Delimiter : sting[10]; Attempts : byte); //То же самое, но запись ведется в строковую переменную. Параметры: переменная, разделитель, какой длинны строки нужно обрабатывать.
UARTx_Write(data_ : byte); //Процедура записи в порт.
UARTx_Write_Text(var uart_text : string[255]); //То же самое, только отсылает строковую переменную.
UART_Set_Active (read_ptr : ^Tread_ptr; write_ptr : ^Twrite_ptr; ready_ptr : ^Tready_ptr; tx_idle_ptr : ^Ttx_idle_ptr); //Выбор модуля UART, который должен быть активным на данный момент (подробнее есть в справке).

А вот после того, как вы вспомнили что представляет из себя UART в mikroPascal, можно и с прерываниями познакомиться. Я и сам не так давно с ними разобрался, так что если где увидите косяк, то сразу пишите в коментах :)

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

В данном случае нас интересуют прерывания по таймеру/счетчику 1. А точнее, из всех прерываний только прерывание по совпадению. Для этого нам нужны такие регистры:

TCCR1B (настраиваем предделитель (1, 8, 64, 256, 1024) , OCR1A (настраиваем компаратор) , TIMSK (выбор прерываний), SREG (регистр статуса).

Теперь, когда знаем зачем нам эти регистры, можно и сконфигурировать их.

TCCR1B:=0x04; //устанавливаем предделитель на 256
OCR1AH:=0x05; //Записываем старший бит регистра сравнения
OCR1AL:=0xdc; //Записываем младший бит регистра сравнения
TIMSK:=0x10; //Выбираем прерывание по совпадению 
SREG_I_bit:=1; //Разрешаем прерывания

Вы скорее всего обратили внимание, что регистр OCR1A странный. Просто он состоит из двух восьмибитных регистров. В итоге его разрядность составляет 16 бит.

Теперь можно создать процедуру для обработки прерываний. Назовем ее Light().

procedure Light(); iv IVT_ADDR_TIMER1_COMPA; //тут мы выбрали, по какое прерывание будет вызывать выполнение процедуры.
begin
     TCNT1H:=0x00; //Обнуляем счетный регистр (он тоже "двойной").
     TCNT1L:=0x00;
end;

Ну вот, основное по части прерываний сделали, а теперь....

program iCPU;

uses AADL;

var c, inp:integer;
    iarr:array [0..3] of integer;
    str:string [10];

procedure Light(); iv IVT_ADDR_TIMER1_COMPA;
begin
     TCNT1H:=0x00;
     TCNT1L:=0x00;
     
     PORTD7_bit:=1;
     delay_ms(10);
     PORTD7_bit:=0;
     if inp<=3 then inc(inp) else inp:=0;
     case inp of
     0:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     1:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     2:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     3:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     end;
end;



begin
TCCR1B:=0x04;
OCR1AH:=0x05;
OCR1AL:=0xdc;
TIMSK:=0x10;
SREG_I_bit:=1;

DDRC:=0xFF;
DDRB:=0xFF;
DDD7_bit:=1;


Uart1_init(9600);

     While TRUE do begin
           if (UART_Data_Ready() = 1) then begin
               UART_Read_Text(str, '/', 10);
               c:=StrToInt(str);
               Str_Cut_Left(str,1);
               if (c>100) and (c<200) then iarr[0]:=StrToInt(str)
               else if (c>200) and (c<300) then iarr[1]:=StrToInt(str)
               else if (c>300) and (c<400) then iarr[2]:=StrToInt(str)
               else if (c>400) and (c<500) then iarr[3]:=StrToInt(str);
           end;
     end;
end.

Вот это все - тело программы. Нет, она не сложная, но много рутинных действий.

Разберем по порядку.

1. Это конфигурация регистров и портов микроконтроллера.

TCCR1B:=0x04; 
OCR1AH:=0x05;
OCR1AL:=0xdc;
TIMSK:=0x10;
SREG_I_bit:=1;

DDRC:=0xFF; //Конфигурируем порт на выход
DDRB:=0xFF; //         ------------//---------------
DDD7_bit:=1; //То же самое, только для конкретного пина.


Uart1_init(9600); //Инициализация UART

2. Далее основной цикл программы.

While TRUE do begin
           if (UART_Data_Ready() = 1) then begin //Ждем данные, если они есть то
               UART_Read_Text(str, '/', 10); //Считываем то что есть, при наличии слеша
               c:=StrToInt(str); //Преобразовываем из строки в числовую переменную "с"
               Str_Cut_Left(str,1); //Обрезаем строку с лева на 1 символ
               if (c>100) and (c<200) then iarr[0]:=StrToInt(str) ,,Перебираем варианты
               else if (c>200) and (c<300) then iarr[1]:=StrToInt(str)
               else if (c>300) and (c<400) then iarr[2]:=StrToInt(str)
               else if (c>400) and (c<500) then iarr[3]:=StrToInt(str);
           end;
end;

В этой процедуре используются такие большие числа (200, 300 и т.д.), так  как формат приходящих данных следующий:

3. И самая большая процедура в программе (и единственная).

procedure Light(); iv IVT_ADDR_TIMER1_COMPA;
begin
     TCNT1H:=0x00;
     TCNT1L:=0x00;
     
     PORTD7_bit:=1; //Здесь мы зажигаем....
     delay_ms(10);
     PORTD7_bit:=0; //И гасим светодиодик.
     if inp<=3 then inc(inp) else inp:=0; 
     case inp of //Методом перебора выбираем нужное действие
     0:begin
            case iarr[inp] of //И снова перебор....
                    1:        begin
                                   PORTB:=0x01; //Тут отсылаем значение в порт В
                                   PORTC:=0x1e; //То же тольков порт С
                              end;
                    2:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x01;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x02;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30); //И задержка в 30 с , что бы было видно, что диод светится.
     end;
     1:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x04;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x08;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     2:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x10;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x20;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     3:begin
            case iarr[inp] of
                    1:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1e;
                              end;
                    2:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1d;
                              end;
                    3:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x1b;
                              end;
                    4:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x17;
                              end;
                    5:        begin
                                   PORTB:=0x40;
                                   PORTC:=0x0f;
                              end;
                    6:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1e;
                              end;
                    7:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1d;
                              end;
                    8:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x1b;
                              end;
                    9:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x17;
                              end;
                    10:        begin
                                   PORTB:=0x80;
                                   PORTC:=0x0f;
                              end;
            end;
            delay_ms(30);
     end;
     end;
end;

Я использовал столько операторов case, так как тут они (на мой взгляд) лучше подходят. Эта процедура отвечает за динамическое обновление картинки (именно по этому и назвал ее Light(); ).

Таймер срабатывает 20 раз в секунду. Это можно посчитать по формуле c(циклов):=31250*t(c). Где с(циклов) - то самое число, которое мы записываем в регистр сравнения. Кстати, в mikroPascal есть полезная утилитка Quick Converter, с помощью которой можно перевести это число из десятичной системы в шестнадцатиричную.Внимание! Формула справедлива только для частоты 8 МГц и предделителя установленного на 256.

Так как у нас четыре столбца светодиодов, то картинка в секунду успевает обновиться 5 раз. Я считаю что этого вполне достаточно, но при желании можно увеличить частоту регенерации "изображения".

Кстати, а вот и схема:

Это устройство в Proteus'e работает, но почему-то частота переключения светодиодов слишком низкая. Скорее всего программа не хочет симулировать работу схемы в реальном времени. После небольших доработок эту схему вполне можно "оживить", что я и планирую сделать в будущем (когда время появится). Но еще раз хочу заметить, это - не готовое устройство, а только "наглядное пособие". До реального прототипа его еще доделывать нужно.

Спасибо всем кто читал мою писанину! Буду рад всем замечаниям и пожеланиям!

Полезные ресурсы:
http://www.gaw.ru/html.cgi/txt/doc/micros/avr/index.htm
http://www.linker.ru/node/1387
http://radiokot.ru/start/mcu_fpga/avr/11/

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

Теги:

Опубликована: 0 1
Я собрал 0 0
x

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

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

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

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

0
Александр #
zeconir, подскажи пожалуйста, что за модуль
uses AADL;
Он присутствует у тебя в этом и других уроках. У меня mikropascal v6 не находит этот модуль. Пишет
Ответить
0
Александр #
Всё, нашёл я эту библиотеку после повторного скачивания архива. Видимо первый архив как то криво скачался!
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется сила тока?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Pickit 2 - USB-программатор PIC-микроконтроллеров
Pickit 2 - USB-программатор PIC-микроконтроллеров
Мультиметр Mastech MS8239C Катушка Тесла
вверх