Справочник по программированию «Bascom-AVR» (М.Л. Кулиш). Справочник по программированию Bascomavr Создание микропроцессорной системы Теория
Скачать 1.18 Mb.
|
Dim Tmpb As Byte 'временные байтовые данные ' ...... 'определим действующие линии портов как константы Const Pcamsk = &B11111111 'порта PA Const Pcbmsk = &B11111111 'порта PB Const Pccmsk = &B00000011 'порта PC Const Pcdmsk = &B00111100 'порта PD ' ...... On Pcint0 Pc_int0 'векторы прерывания от изменения уровней на линиях портов On Pcint1 Pc_int1 On Pcint2 Pc_int2 On Pcint3 Pc_int3 ' ...... 'настроить систему Pcicr = &B00001111 'разрешим прерывания от изменения уровны во всех портах Pcmsk0 = Pcamsk 'определим действующие линии портов: порта PA Pcmsk1 = Pcbmsk 'порта PB Pcmsk2 = Pccmsk 'порта PC Pcmsk3 = Pcdmsk 'порта PD Dub_pa = Pina And Pcamsk 'запомнить текущее состояние линий портов Dub_pb = Pinb And Pcbmsk Dub_pc = Pinc And Pccmsk Dub_pd = Pind And Pcdmsk Enable Interrupts ' ...... 'главный цикл Mc: If Num_port <> 0 Then Print Num_port : Num_port = 0 End If Goto Mc '-------------------------------------- 'программы обработки прерываний от изменения уровня, сообщающие главной программе 'о наличии изменения ненулевым значением переменной Num_port '-------------------------------------- 'по линиям порта A Pc_int0: Tmpb = Pina Xor Pcamsk : Tmpb = Pina Xor Dub_pa : Num_port = 0 Gosub Search_pin 'добавить в Num_port номер позиции единицы Return '-------------------------------------- 'по линиям порта B Pc_int1: Tmpb = Pinb Xor Pcbmsk : Tmpb = Pinb Xor Dub_pb : Num_port = 8 Gosub Search_pin 'добавить в Num_port номер позиции единицы Return '-------------------------------------- 'по линиям порта C Pc_int2: Tmpb = Pinc Xor Pccmsk : Tmpb = Pinc Xor Dub_pc : Num_port = 16 Gosub Search_pin 'добавить в Num_port номер позиции единицы Return '-------------------------------------- 'по линиям порта D Pc_int3: Tmpb = Pind Xor Pcdmsk : Tmpb = Pind Xor Dub_pd : Num_port = 24 Gosub Search_pin 'добавить в Num_port номер позиции единицы Return '-------------------------------------- 'подпрограмма поиска "1" в измененного уровня, на самом деле, это преобразование 'позиционного кода в Tmpb в двоичный в Num_port. Методом сдвига вправо и искремента результата ============================================================================= 30 ===================================== Справочник по программированию «Bascom-AVR» == Search_pin: While Tmpb <> 0 'повторять пока регистр Tmpb не станет равным нулю Shift Tmpb , Right : Incr Num_port Wend Return '---------------------------------------------------------------------------------- Обработчик прерывания, написанный без применения ассемблера, не может иметь оптимального кода. Это показывает дисассемблированный текст (пример 6). Мы видим, что обработчик с одной стороны не выполняет недопустимых действий, а с другой – имеет явную избыточность и расточителен. Пример 6 - Ассемблерный текст обработчика прерывания (листинг) из программы примера 5, получаемый при компиляции Bascom-AVR '---------------------------------------------------------------------------------- Pc_int0: ;сохранение регистрового блока push r0 push r1 push r2 push r3 push r4 push r5 push r7 push r10 push r11 push r16 push r17 push r18 push r19 push r20 push r21 push r22 push r23 push r24 push r25 push r26 push r27 push r28 push r29 push r30 push r31 in r24,$3F push r24 ;Tmpb = Pina Xor Pcamsk in r16,$0 ldi r20,#255 eor r16,r20 ldi r26,#5 ldi r27,#1 st x,r16 ;Tmpb = Pina Xor Dub_pa in r16,$0 lds r20,$101 eor r16,r20 ldi r26,#5 ldi r27,#1 st x,r16 ;Num_port = 0 ldi r24,#0 sts $100,r24 ;Gosub Search_pin 'добавить в Num_port номер позиции единицы call 0000036A ;восстановление регистрового блока pop r24 out $3F,r24 pop r31 pop r30 pop r29 pop r28 pop r27 pop r26 pop r25 pop r24 pop r23 pop r22 pop r21 ============================================================================= 31 ===================================== Справочник по программированию «Bascom-AVR» == pop r20 pop r19 pop r18 pop r17 pop r16 pop r11 pop r10 pop r7 pop r5 pop r4 pop r3 pop r2 pop r1 pop r0 ;Return Reti ;------ ;подпрограмма Search_pin: 0000036A: While Tmpb <> 0 'повторять пока регистр Tmpb не станет равным нулю lds r16,$105 cpi r16,#0 brne 00000376 jmp 0000038E 00000376: ;Shift Tmpb , Right ldi r25,#1 ldi r26,#5 ldi r27,#1 call 000003C6 ;вызов библиотечной программы ;Incr Num_port ldi r26,#0 ldi r27,#1 ld r24,x subi r24,#255 st x,r24 ;Wend jmp 0000036A 0000038E: ret ;------ ;библиотечная подпрограмма сдвига вправо на число в R25 000003C6: cpi r25,#0 breq 000003D4 ld r24,x 000003CC: lsr r24 dec r25 brne 000003CC st x,r24 000003D4: ret '---------------------------------------------------------------------------------- ============================================================================= 32 ===================================== Справочник по программированию «Bascom-AVR» == Вопросы и ответы (1-10) --------------------------------------------------------------------------------------------------------------------------------------------------- Вопрос 1 Но вот не могу понять только одного, почему в такой короткой программе, как эта: Dim A As Byte For A=1 to 30 Print A Next A End …при компиляции размер кода составляет более 300 байт?? Абсурд! Баском конечно кушает память, но чтобы так!.. Может я в чём не прав? Ответ 1 1 Насчет размера вашего примера. Такой же будет для любого компилятора. В этот размер входит: - заголовок программы, включаемый в код автоматически (по умолчанию) и содержащий место под все вектора прерывания по 4 байт на вектор, очистку памяти 20-30 байт и инициализацию оборудования 30 - 100 байт; - библиотека используемой функции и плюс 2-3 стандартных - около 100 байт; - и собственно код вашей программы. Т.е. все сходится. Зато еще один вызов данной функции приводит к добавлению всего 20 - 30 байт. --------------------------------------------------------------------------------------------------------------------------------------------------- Вопрос 2 Да и вообще, здесь много подводных камней, про которые даже в pdf-файле не найдешь…Я изучал когда-то давно Бейсик, сейчас плохо помню, приходиться заново учить. К какому Бейсику ближе Баском? Ответ 2 Синтаксис и мнемоника, в принципе, отвечают стандарту Basic для DOS с учетом особенностей, ограниче- ний и дополнительных возможностей. Лучше на стандартный Basic не ориентироваться. Слишком много ограни- чений, обусловленных различными возможностями процессоров. Главное отличие в том, что нужно определить тип переменных заранее, не допускать скрытого преобразования типов и не применять больше одного действия в одном операторе.) Лучше ориентироваться на оригинальное описание Bascom-AVR – оно отличное. На русском имеется только описание Bascom-8051. И еще на примеры - их очень много. -------------------------------------------------------------------------------------------------------------------------------------------------- Вопрос 3 Я сначала ничего не подозревал. Пытался спокойно делать себе программки в Баскоме, как вдруг понял, что реализация протокола I2C(TWI) в любом микроконтроллере происходит программно, независимо от того, есть ли в нём аппаратная поддержка данного протокола или нет. Я бы ничего этого не заметил, если бы не наткнулся на проблему нехватки памяти микроконтроллера. В конечном итоге выяснилось, что реализация аппаратного прото- кола возможна только в лицензионной версии Баскома, так как в демо-версии нет соответствующей библиотеки. Ответ 3 По моему наблюдению, использование аппаратного контроллера с точки зрения размера кода совершенно неэффективно. При программной реализации размер кода получается равноценным. Потому, что работа с аппа- ратным портом конечно проще, но при этом требуется организовать обработку соответствующего прерывания. Преимущество аппаратного I2C только в возможности осуществлять "прозрачную" работу одновременно с други- ми процессами и при наличии очень медленных устройств. Когда, например, в фоновом режиме нужно постоянно считывать или дописывать данные. При этом в коде "весит" именно программа организации МАССИВА записы- ваемых или считываемых данных, а не сам драйвер. Вот пример работающей программы на BAS и на ASM. В ос- новной программе применяются готовые функции. В прерывании используется ассемблерная программа (а ее размер минимален). Если устройство более медленное - нужно вместо NOP-ов добавить в программу подпро- граммы более продолжительной задержки. Не забывать, что когда работаешь с I2C, нужно бы запретить прерыва- ния. Если длительность импульса SCL превысит 10 мкс устройство может само отключится! В последующем примере переключение уровней делается изменение направления порта. Это важно. Так можно манипулировать с им намного быстрее. '-------------------------------------------------------------- ============================================================================= 33 ===================================== Справочник по программированию «Bascom-AVR» == ' Программы обслуживания АЦП типа ADS1110 (Burr-Broun) '-------------------------------------------------------------- ' результаты ' 1 смещение входа имеется и весьма заметно 1-2 мВ. Зависит от включенного коэффициента усиления ' 2 При усилении К=1 шум меньше 1 дискрета, что делает усреднение бесполезным ' 3 При максимальном усилении К=8 шум составляет около 20-30 мкВ пик-пик '-------------------------------------------------------------- Config Sda = Portc.1 'линия данных Config Scl = Portc.0 'линия синхронизации Config I2cdelay = 1 'наивысшая скорость '----------------------------- 'АВТООПРЕДЕЛЕНИЕ АДРЕСА АЦП Find_adr: Adradc = 142 'АДРЕС НУЛЕВОЙ ПРОШИВКИ(90h -2) Disable Interrupts 'запретить прерывания Findadr1: Adradc = Adradc + 2 'АДРЕС ДЛЯ ЧТЕНИЯ + 2 If Adradc <> 160 Then Goto Findadr2 'ПРОВЕРИМ НА МАКСИМУМ(90h + 16) End If Adradc = 144 'АДРЕС НУЛЕВОЙ ПРОШИВКИ (90h) Goto En_intr 'НА ВЫХОД ЕСЛИ ВСЕ АДРЕСА ПРОЙДЕНЫ Findadr2: $asm Lds R31 , {Adradc} 'АДРЕС ДЛЯ ЧТЕНИЯ Inc R31 Rcall Start_bit 'СТАРТ, ДАННЫЕ И ЖДЕМ ПОДТВЕРЖДЕНИЯ '------------ Rcall R_byte 'ПРИМЕМ СТАРШИЙ БАЙТ Rcall Mstr_ack 'ВЫДАЧА СИГНАЛА ПОДТВЕРЖДЕНИЯ Rcall R_byte 'ПРИМЕМ МЛАДШИЙ БАЙТ Rcall Mstr_ack 'ВЫДАЧА СИГНАЛА ПОДТВЕРЖДЕНИЯ Rcall R_byte 'ПРИМЕМ СТАТУС Rcall No_ack 'ДА - БЕЗ ПОДТВЕРЖДЕНИЯ И СФОРМИРУЕМ СТОП-БИТ Andi R31 , &B01100000 'АНАЛИЗИРУЕМ D5 И D6. ВСЕГДА Д.Б. = 0 Brne Findadr1 'ЕСЛИ НЕ НУЛЬ - ПОВТОРИТЬ $end Asm Goto En_intr 'НА ВЫХОД ЕСЛИ АДРЕС НАЙДЕН '------------------------------------------ 'п/п записи статуса АЦП ADS1110 (нормальный медленный режим) 15 изм/с. Шкала 1.024 В Slow_adc: ' ------------ Запуск преобразования: 1 только в одиночном ' | --------- Запуск: 0 - автоматический, 1 - одиночное ' | | ' | | ------- Скорость: 00 - 240 SPS, 01 - 60 SPS ' | | | 10 - 30 SPS, 11 - 15 SPS ' | | | ' | | | ----- Усиление: 00 - 1 , 01 - 2 ' | | | | 10 - 4 , 11 - 8 ' | | | | ' | ||||| Value = &B00001101 Wr_adc: Disable Interrupts 'запретить прерывания I2cstart 'старт I2cwbyte Adradc 'байт адреса I2cwbyte Value 'байт режима I2cstop 'стоп $asm 'подготовить порты к дальнейшему использованию ассемблерной программой Cbi Ddrc , 0 'установим на Scl плавающую "1" Cbi Portc , 0 'подготовим "0" для вывода Cbi Ddrc , 1 'установим на Sda плавающую "1" Cbi Portc , 1 'подготовим "0" для вывода $end Asm En_intr: Enable Interrupts 'разрешить прерывания Return '------------------------------------------ 'п/п записи статуса АЦП ADS1110 (быстрый режим) 240 изм/с. Шкала 1.024 В Speed_adc: ' ------------ Запуск преобразования: 1 только в одиночном ' | --------- Запуск: 0 - автоматический, 1 - одиночное ' | | ' | | ------- Скорость: 00 - 240 SPS, 01 - 60 SPS ' | | | 10 - 30 SPS, 11 - 15 SPS ' | | | ' | | | ----- Усиление: 00 - 1 , 01 - 2 ' | | | | 10 - 4 , 11 - 8 ============================================================================= 34 ===================================== Справочник по программированию «Bascom-AVR» == ' | | | | ' | ||||| Value = &B00000001 Goto Wr_adc '------------------------------------------ 'п/п записи статуса АЦП ADS1110 (нормальный режим) 15 изм/с. Шкала 2.048 В Wide_adc: ' ------------ Запуск преобразования: 1 только в одиночном ' | --------- Запуск: 0 - автоматический, 1 - одиночное ' | | ' | | ------- Скорость: 00 - 240 SPS, 01 - 60 SPS ' | | | 10 - 30 SPS, 11 - 15 SPS ' | | | ' | | | ----- Усиление: 00 - 1 , 01 - 2 ' | | | | 10 - 4 , 11 - 8 ' | | | | ' | ||||| Value = &B00001100 Goto Wr_adc '------------------------------------------ 'ЧТЕНИЕ ДАННЫХ ИЗ АЦП В R27(ст), R26(мл), статус в R31 Rd_adc: $asm ' Cbi Ddrc , 0 'установим на Scl плавающую "1" ' Cbi Portc , 0 'подготовим "0" для вывода ' Cbi Ddrc , 1 'установим на Sda плавающую "1" ' Cbi Portc , 1 'подготовим "0" для вывода Lds R31 , {Adradc} 'АДРЕС ДЛЯ ЧТЕНИЯ Inc R31 Rcall Start_bit 'СТАРТ, ДАННЫЕ И ЖДЕМ ПОДТВЕРЖДЕНИЯ '------------ Rcall R_byte 'ПРИМЕМ СТАРШИЙ БАЙТ Mov R29 , R31 'ЗАПИШЕМ ДАННЫЕ В ОЗУ Rcall Mstr_ack 'ВЫДАЧА СИГНАЛА ПОДТВЕРЖДЕНИЯ Rcall R_byte 'ПРИМЕМ МЛАДШИЙ БАЙТ Mov R28 , R31 'ЗАПИШЕМ ДАННЫЕ В ОЗУ Rcall Mstr_ack 'ВЫДАЧА СИГНАЛА ПОДТВЕРЖДЕНИЯ Rcall R_byte 'ПРИМЕМ СТАТУС Rjmp No_ack 'ДА - БЕЗ ПОДТВЕРЖДЕНИЯ И СФОРМИРУЕМ СТОП-БИТ '------------------------------------------ 'порты PC.0, PC1 инициализированы на ввод (исходно DDRC.0 = 0, DDRC.1 = 0), 'а в порты PORTC.0 PORTC.1 записывается "0". Таким образом на линиях устанавливается "1". 'воспроизведение "0" производися переключением направления '------------------------------------------ ' Portc.0 - Scl, Portc.1 - Sda '------------------------------------------ 'ФОРМИРОВАНИЕ СТАРТ-БИТА И ЕЩЕ ДВЕ ОПЕРАЦИИ Start_bit: Cbi Ddrc , 0 'УСТАНОВКА И ОЖИДАНИЯ ОТПУСКАНИЯ ЛИНИИ Scl_l Nop '------------------ Nop ' ¦ ¦ Cbi Ddrc , 1 '--- - Nop 'Scl----------------- Nop ' Sbi Ddrc , 1 '------------- Nop ' ¦ ¦ Nop '------- ------ Sbi Ddrc , 0 'Sda----------------- '-------------------------- 'ВЫДАЧА НА ЛИНИЮ БАЙТА ДАННЫХ ЗАПИСАННЫХ В R31 T_byte: Ldi R30 , 8 'ЧИСЛО БИТ T_by0: Sbi Ddrc , 0 'ЦИКЛ ПЕРЕДАЧИ Rol R31 'СДВИГ Brcc T_by1 Cbi Ddrc , 1 'порт в "1" Rjmp T_by2 T_by1: Sbi Ddrc , 1 'порт в "0" T_by2: 'УСТАНОВКА И ОЖИДАНИЯ ОТПУСКАНИЯ ЛИНИИ Scl_l Cbi Ddrc , 0 '- ----- - - -- ----- Dec R30 ' ¦ ¦ ¦ ¦ ¦ ¦ Brne T_by0 '------ ---- ---- 'Scl-------------------------------- ' '---- ---------- --- - - --- ------- |