Реклама ⓘ
Главная » Микроконтроллеры
Призовой фонд
на апрель 2024 г.
1. 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

AVR-программатор USB ASP
AVR-программатор USB ASP
МиниПК MK809V - 4 ядра, Android 4.4.2 Arduino UNO
вверх