Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Программа для микроконтроллера
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
Aleksandr_KPI
Здравствуйте.

Мне нужно запрограммировать МК C8051F020. В ассемблере я не силен, а с Си доводилось работать, поэтому решил использовать последний. Скачал книгу: Магда Ю.С. "Микроконтроллеры серии 8051: практический подход". По ней и планирую программировать. В процессе изучения возник вопрос касательно применения ассемблера в коде Си (в книге говорится может понадобится). Код:

Цитата
#pragma asm

SETB ET0;
SETB EA;

#pragma endasm;


SETB EA - запрет на любые прерывания, а что такое SETB ET0.
toweroff
Цитата(Aleksandr_KPI @ Apr 14 2010, 19:08) *
Здравствуйте.

Мне нужно запрограммировать МК C8051F020. В ассемблере я не силен, а с Си доводилось работать, поэтому решил использовать последний. Скачал книгу: Магда Ю.С. "Микроконтроллеры серии 8051: практический подход". По ней и планирую программировать. В процессе изучения возник вопрос касательно применения ассемблера в коде Си (в книге говорится может понадобится). Код:



SETB EA - запрет на любые прерывания, а что такое SETB ET0.

ну наверное EnableTimer0

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


Цитата
#include <stdio.h> #include <stdio.h>
#include <REG52.h>




sbit Bit0 = P1^0;
void INT0Isr (void) interrupt 0 using 1 {

EX0 = 0;
Bit0 = ~ Bit0;
printf("Interrupt 0 occured. \n");
EX0 = 1;
}


void main (void)

{

SCON = 0x50;
TH1 = 0xFD;
TMOD |= 0x20;
TR1 = 1;
TI = 1;

IT0 = 1;
EX0 = 1;
EA = 1;


while (1);


}


При выполнении в пошаговом режиме не инвестируется бит порта Р1 и в порт не выдается значение.
Палыч
Цитата(Aleksandr_KPI @ Apr 15 2010, 17:47) *
Выполнил программу по учебнику, а она работает не до конца.
При выполнении в пошаговом режиме не инвестируется бит порта Р1 и в порт не выдается значение.
Инвертироваться значение Р1.0 должно в прерывании от таймера, при этом ещё должно(?) выводиться сообщение "Interrupt 0 occured." (не знаю только вот куда должно выводиться: на терминал(?), судя по всему). Возможно, в пошаговом режиме Вы просто не дождались момента, когда таймер отсчитает нужное время... Чем Вы там пользуетесь для отладки Вашей программы? Можно ли поставить точку останова в процедуру обработки прерывания от таймера и запустить программу в автомате? Остановится ли программа на точке останова?
Aleksandr_KPI
Цитата
Чем Вы там пользуетесь для отладки Вашей программы?


Использую среду Keil uVision.

Цитата
Можно ли поставить точку останова в процедуру обработки прерывания от таймера и запустить программу в автомате? Остановится ли программа на точке останова?


Честно сказать, я не знаю как это сделать. Программу я запускал и в пошаговом и в непрерывном режимах, результат отрицательный.
MrYuran
Возможно, что периферия не симулируется, либо симулируется с ошибками.
Бросайте хренью заниматься, возьмите реальную железку.
Aleksandr_KPI
Цитата
Бросайте хренью заниматься, возьмите реальную железку.


Так, а на реальной железке писать программу методом проб и ошибок, ее ведь откомпилировать нужно.
MrYuran
Цитата(Aleksandr_KPI @ Apr 16 2010, 11:43) *
ее ведь откомпилировать нужно.

естественно, а до этого ещё и написать.
Aleksandr_KPI
Цитата
Бросайте хренью заниматься, возьмите реальную железку.


Цитата
естественно, а до этого ещё и написать.

Тогда я не понял сути. Что Вы имеете ввиду?
MrYuran
Цитата(Aleksandr_KPI @ Apr 16 2010, 11:50) *
Тогда я не понял сути. Что Вы имеете ввиду?

Я имею в виду, что нужно поставить задачу и попытаться её решить.
Хотя бы с/д моргнуть. А лучше чего-нибудь посущественней.
Игры с симулятором с примерами из учебника мало что дают в плане обучения.

Вот к примеру, что делает ваша программа?
Инициализировала порт и тупо зависла в бесконечном цикле.
А вы чего-то ждёте.

Ну сделайте хотя бы софтовую задержку, тогда и в симуляторе увидите результат.
Aleksandr_KPI
Цитата
Я имею в виду, что нужно поставить задачу и попытаться её решить.
Хотя бы с/д моргнуть. А лучше чего-нибудь посущественней.
Игры с симулятором с примерами из учебника мало что дают в плане обучения.


Задача есть, он для этого нужны азы.

Цитата
Вот к примеру, что делает ваша программа?
Инициализировала порт и тупо зависла в бесконечном цикле.
А вы чего-то ждёте.


Из книги:
Цитата
В этой программе используется программа обработчик внешнего прерывания 0 (INT0). Каждый раз при возникновении прерывания в последовательный порт выводится соответствующее сообщение и инвертируется бит 0 порта P1.


Цикл я убрал и выяснил, что программа не выполняет прерывание (откомпилировал пошагово). Выходит код не правильный в примере?
MrYuran
Цитата(Aleksandr_KPI @ Apr 16 2010, 12:24) *
Цикл я убрал и выяснил, что программа не выполняет прерывание (откомпилировал пошагово). Выходит код не правильный в примере?

А внешнее воздействие вы на INT0 выдаёте?
Иначе на что он должен реагировать?
Aleksandr_KPI
По задумке автора прерывание вызывается программно.

Цитата
IT0 = 1;
EX0 = 1;
EA = 1;
MrYuran
Цитата(Aleksandr_KPI @ Apr 16 2010, 13:49) *
По задумке автора прерывание вызывается программно.

Ну а если руками за ноги подёргать?
Я бы за два дня там все галки бы поотжимал...
Aleksandr_KPI
Я не понял, выражайтесь яснее.
MrYuran
Цитата(Aleksandr_KPI @ Apr 16 2010, 14:29) *
Я не понял, выражайтесь яснее.

Ну вот у вас там окошечки с регистрами периферии.
Попробуйте подёргать за ноги, соответствующие INT0 - а вдруг сработает?
Aleksandr_KPI
Биты прерывания устанавливаются нормально, не происходит собственно само прерывание. Может дело в обрезанной версии пакета keil при компиляции он пишет, что лимит запускаемого кода 2К.

P.S. Пока я не нашел откуда скачать полную версию Keil uVision, что бы проверить эту теорию.
Hellper
watchdog отключите:

Код
PCA0MD &= ~0x40;
Aleksandr_KPI
Выдает ошибку.

Код
error C202: 'PCA0MD': undefined identifier
Hellper
Код
   WDTCN = 0xDE;                       // Disable watchdog timer
   WDTCN = 0xAD;


вот так. соррри.
Aleksandr_KPI
Странно, пишет:

Код
error C202: 'WDTCN': undefined identifier
          error C202: 'WDTCN': undefined identifier
Hellper
Код
#include <C8051F020.h>
Aleksandr_KPI
Сначала выдавало ошибку:
Код
Error C231 Redefinition


Я исправил, запустил, а результат тот же: прерывание отсутствует.
Aleksandr_KPI
Разобрался, MrYuran был прав.

Цитата
Ну вот у вас там окошечки с регистрами периферии.
Попробуйте подёргать за ноги, соответствующие INT0 - а вдруг сработает?


Я прерывание не на том порту вызывал, книга о одном микроконтроллере, а я другой в программе указал.
Но всетаки один момент не работает, в последовательный порт после инвертирования битов не выдается сообщение.
Код
printf("Interrupt 0 occured. \n");
MrYuran
Цитата(Aleksandr_KPI @ Apr 20 2010, 16:46) *
Но всетаки один момент не работает, в последовательный порт после инвертирования битов не выдается сообщение.
Код
printf("Interrupt 0 occured. \n");

А это надо ручками putchar() написать, скорее всего.
Или заполнить содержанием готовую обёртку.
Но это неправильный подход. printf() выдаёт строку посимвольно, и для каждого символа вызывает putchar().
В случае с УАРТом это будет неоправданные потери времени.
Лучше использовать sprintf(), который формирует строку в буфере, а потом буфер отправлять в УАРТ.
Aleksandr_KPI
Цитата
Но это неправильный подход. printf() выдаёт строку посимвольно, и для каждого символа вызывает putchar().


Спасибо за рекомендацию.

С проблемой я разобрался. Версия keil uvision с глюками. Она выводит в последовательный порт данные в белом цвете и 732 шрифтом smile.gif smile.gif . Не знаете где можно скачать нормальную версию?
Aleksandr_KPI
Подскажите как правильно понимать работу регистра SBUF. Есть код:

Код
#include <stdio.h>
#include <string.h>
#include <REG52.H>

void fputchar (unsigned char c1)
{
  SBUF = c1;
    while (!TI);
      TI = 0;
}

void main(void)
{
  idata char src[] = "Output string";
  idata char *psrc = src;
  int len, cnt;

     SCON = 0x50;
      TH1 = 0xFD;
    TMOD |= 0x20;
      TR1 = 1;
       TI = 0;
      len = strlen(src);

for (cnt = 0; cnt < len; cnt++)
{
   fputchar(*psrc);
   psrc++;
}

while(1);


Когда запускаю в пошаговом режиме в последовательный порт не выводит ничего при достижении команды:
Код
SBUF = c1;

Нажимаю RUN выводит Output string.
MrYuran
Цитата(Aleksandr_KPI @ Apr 21 2010, 12:15) *
Когда запускаю в пошаговом режиме в последовательный порт не выводит ничего при достижении команды:
Код
SBUF = c1;

Нажимаю RUN выводит Output string.

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

Дошел до работы с вставками ассемблерного кода в код Си. При сборке выдает ошибку:
Цитата
linking...
*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL
SYMBOL: ?C_STARTUP
MODULE: Prog2.obj (PROG2)
Program Size: data=18.0 xdata=0 code=61


Читал на официальном сайте о проблеме, но как исправить не понял.
Aleksandr_KPI
Вот нашел на одном форуме:

Цитата
Короче, не используйте #pragma asm в кейле. Я не использую. Оно как-то плохо на него реагирует. Либо перепишите процедуру на си либо создаёте отдельный .asm файл и должным образом его оформляете со всеми директивами типа SEGMENT, extrn global и т.п.

Так что использовать не удастся.

Подскажите почему при выполнении следующего кода:
Код
NAME PROCS
      T2CON EQU 0C8h
      RCAP2H EQU 0CBh
      RCAP2L EQU 0CAh
CSEG AT 0
USING 0
JMP start
SerINT:
ORG 23h
JBC RI, RCV
RETI
RCV:
MOV P1, SBUF
RETI
;——————————————
start:
MOV P1, #0h
MOV SCON, #50h
CLR T2CON.0
CLR T2CON.1
SETB T2CON.4
SETB T2CON.5
MOV RCAP2H, #0FFh
MOV RCAP2L, #0B2h
SETB T2CON.2
SETB ES
SETB EA
SETB TI
SJMP $


В порте Р1 всегда установлены в единицу 4 и 5 биты.
Палыч
Цитата(Aleksandr_KPI @ Apr 23 2010, 11:17) *
Подскажите почему при выполнении следующего кода... В порте Р1 всегда установлены в единицу 4 и 5 биты.

Если посмотреть на Ваш код, то легко увидеть, что регистр Р1 изменяется в двух местах Вашей программы: 1) в main заносится ноль 2) в прерывании заносится содержимое SBUF. Очевидно, что биты Р1.4 и Р1.5 и устанавливаются командой в прерывании (копируются из SBUF), а в SBUF эти биты установлены. Почему в SBUF эти биты установлены? Издалека сказать трудно... Но с этим SBUF - некоторая беда (разработчики МК немножко намудрили). Дело в том, что в МК два регистра под одним адресом и именем SBUF - один для принятых данных (приёмника - можно только читать), другой - для передаваемых данных (передатчика - можно только записывать в него). Помниться (а, может быть я - не прав), что в окошке Keil "Serial channel" изменяется как раз второй (для передачи) регистр SBUF. Если Вы отлаживая свою программу изменяли значение в этом окне, то в регистре SBUF, куда должны помещатся принятые данные (SBUF приёмника) - изменений не происходит. А копируете Вы в Р1 как раз SBUF приёмника. Чтобы изменить SBUF приёмника, нужно что-нибуть набрать в окне Keil "Serial Window".
Ещё мне кажется, что Вы настроили неверно UART. В регистр SCON Вы заносите 50h: один бит -разрешает работу приёмника; второй - устанавливает режим работы. Имхо, Вы установили режим работы 2. Скорость работы UART в режиме 2 задаётся только тактовой частотой МК и не регулируется. Так и было задумано? Зачем тогда настройка таймера 2?

PS. C настройками UART - всё верно: устанавливается режим 1. Это - я за давностью использования МК51 запамятовал...
Aleksandr_KPI
Цитата
Помниться (а, может быть я - не прав), что в окошке Keil "Serial channel" изменяется как раз второй (для передачи) регистр

Окно "Serial channel" я открыл только для того что бы следить за изменением флагов прерываний передатчика и приемника последовательного порта и за ходом выполнения программы. Регистр SBUF при исполнении программы никак не изменяется (там постоянно висят нули) даже когда я захожу на вкладку последовательного порта и ввожу число, оно в нем не появляется.

Цитата
Если Вы отлаживая свою программу изменяли значение в этом окне, то в регистре SBUF, куда должны помещатся принятые данные (SBUF приёмника) - изменений не происходит. А копируете Вы в Р1 как раз SBUF приёмника. Чтобы изменить SBUF приёмника, нужно что-нибуть набрать в окне Keil "Serial Window".


В этом окне я ничего не менял.
В принципе то программа работает. Вводимое мной число (от 0 до 9) в вкладке последовательного порта, четко отображается с помощью первых 4 разрядов порта Р1. Вот только при этом загадочно "горят" 4 и 5 биты.
Палыч
Цитата(Aleksandr_KPI @ Apr 23 2010, 14:04) *
Регистр SBUF при исполнении программы никак не изменяется (там постоянно висят нули) даже когда я захожу на вкладку последовательного порта и ввожу число, оно в нем не появляется.
Я об этом и писал: отображается SBUF передатчика, но не приёмника (он вообще не отображается на окошках).

Цитата(Aleksandr_KPI @ Apr 23 2010, 14:04) *
В принципе то программа работает. Вводимое мной число (от 0 до 9) в вкладке последовательного порта, четко отображается с помощью первых 4 разрядов порта Р1. Вот только при этом загадочно "горят" 4 и 5 биты.
Кажется понимаю - в чём дело... Кагда Вы нажимаете на клавиатуре клавишу "1", находясь в окне "Serial Window" - то посылается байт (код ASCII), соответствующий символу "1". Этот байт имеет значение 31h. Клавиша "2" - код 32h, и т.д. Вот в разрядах 4 и 5 единички и висят.
Aleksandr_KPI
Да. Спасибо, Вы абсолютно правы. smile.gif
Aleksandr_KPI
Перешел из пакета keil uvision3 в keil uvision4 и возникла проблема с компиляцией проекта. Код в обоих случаях одинаковый, но при работе в 4 keil-е выдает ошибку C100. Суть ошибки: из части кода на Си вызывается процедура написана на ассемблере, при этом компилятор ругается на эту процедуру не видя ее. В keil uvision3 взаимное "виденье" двух частей кода обеспечивал сам пакет. Кто работает в keil uvision4 подскажите как устранить ошибку. На фото проект из keil uvision3 (рабочий). В keil uvision4 отсутствуют каталоги stdio.h и reg52.h в окне Project Workspce.
Aleksandr_KPI
Подскажите почему программа выдает ошибку error A9: SYNTAX ERROR. Ругается на все строки, кроме первой. Программа для микроконтроллера AT89S8252.
Часть кода:

Код
BYTE_ERR_IN     EQU     02AH
ERR_56M         REG     BYTE_ERR_IN.0
ERR_G1_4        REG     BYTE_ERR_IN.1
ERR_SNPR56M     REG     BYTE_ERR_IN.2
SNPR_GHM        REG     BYTE_ERR_IN.3
ERR_SNPRK56M    REG     BYTE_ERR_IN.4
ERR_SNPRB56M    REG     BYTE_ERR_IN.5
ERR_OG          REG     BYTE_ERR_IN.6
ERR_NLCHM       REG     BYTE_ERR_IN.7
Палыч
Не знаю - что Вы здесь задумали, но к битам байта ОЗУ с адресом 2Аh нельзя обращаться побитово.
Aleksandr_KPI
Программа не моя, попросили коечто изменить, выдали только листинг в WORD. Я его скопировал в Keil, а он выдал ошибки. Заменил REG на EQU (не знаю на сколько это правильно) и все заработало.
Aleksandr_KPI
Подскажите в чем может быть ошибка. Практически в конец программы добавляю вызов двух меток RESET_BOCH, RESET_BNCH и программа сразу же начинает работать не правильно. При пошаговой компиляции с строки 171 она переходит не на 172, а на 180 (на эти строки я ставлю метки, что бы не смотреть пошагово на задержку). Потом программа странным образом перезагружается с метки mein. И только после этого переходит с 171 она переходит на 172 строку. А дальше зависает в какомто непонятном цикле. Не могу понять как влияет добавление двух переходов на работу всей программы, к которым она даже на доходит. Если эти метки убрать, все работает нормально.
Палыч
Цитата(Aleksandr_KPI @ Apr 30 2010, 18:03) *
Подскажите в чем может быть ошибка.
Имхо, под стек места мало отвели, причем место под стек перекрывается с адресами регистров общего назначения.

Ещё совет: если прикрепляете к сообщению текст программы - так и прикрепляйте ассемблерный файл (или если есть необходимость - файл листинга). Не надо создавать вордовский файл - он абсолютно нечитаем...
Aleksandr_KPI
Подскажите, как код передает данные во внешнюю память:

Код
ERR_EXT_ADDR_OUT        EQU    001H
...............

BYTE_ERR_OUT    EQU     02CH
KVITANCIA8      REG     BYTE_ERR_OUT.1  
LED_IND         REG     BYTE_ERR_OUT.2
WR_SETKA        REG     BYTE_ERR_OUT.6  
WR_DDS          REG     BYTE_ERR_OUT.7  

...............
  
            MOV    R0,#ERR_EXT_ADDR_OUT
            MOV    A,BYTE_ERR_OUT
            MOVX   @R0,A


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

Извините что-то файл не прикрепился.
demiurg_spb
Цитата(Aleksandr_KPI @ Jun 7 2010, 15:07) *
Подскажите, как код передает данные во внешнюю память:
Код
            MOV    R0,#ERR_EXT_ADDR_OUT
            MOV    A,BYTE_ERR_OUT
            MOVX   @R0,A

MOVX через косвенную адресацию поместит содержимое аккумулятора в ячейку памяти по адресу, хранящемуся в регистре R0.
Поскольку этот регистр восьмибитный то и диапазон адресов невелик 0-255.
При использовании MOVX интерфейс внешней памяти контроллера будет самостоятельно вырабатывать управляющие сигналы WR RD ALE в соответствии с даташитом на контроллер. Для понимания этого процесса советую почитать доку на Ваш контроллер и что-нибудь об параллельном интерфейсе 8085.
Aleksandr_KPI
Цитата
MOVX через косвенную адресацию поместит содержимое аккумулятора в ячейку памяти по адресу, хранящемуся в регистре R0.


Это я понимаю. Почему передача данных ведется через порт P0, а не скажем через порт P1 или P2?
Палыч
Цитата(Aleksandr_KPI @ Jun 8 2010, 14:55) *
Почему передача данных ведется через порт P0, а не скажем через порт P1 или P2?
Потому, что разработчики МК51 так когда-то спроектировали работу МК с внешней памятью: адрес - на портах Р0 и Р2, данные - на Р0
Aleksandr_KPI
Цитата
Потому, что разработчики МК51 так когда-то спроектировали работу МК с внешней памятью: адрес - на портах Р0 и Р2, данные - на Р0


У меня в данном примере данные и адрес передаются по одному порту P0. А как быть в другом случае, например мне нужно написать программу для передачи данных из МК в ПЛИС и наоборот. Имеется два порта Р6 и Р7 микроконтроллера C8051F020. По седьмому порту передаются данные по шестому адрес. Для передачи данных в ПЛИС тоже используется команда MOVX или можно просто передавать данные побайтно в порты? Я не совсем понял выражение :
Цитата
адрес - на портах Р0 и Р2
. Как использовать команду MOVX если адрес и данные на разных портах?
Палыч
Цитата(Aleksandr_KPI @ Jun 10 2010, 17:38) *
Как использовать команду MOVX если адрес и данные на разных портах?
Вы используете C8051F020. Это какой-то клон 8051 (к сожалению, с C8051F020 я не знаком). В классическом 8051 по команде MOVX МК аппаратно формирует некую, описанную в DS, последовательность сигналов адреса (на Р0, Р2), данных (на Р0), сигналов ALE, RD, WR. Скорее всего (уточните в DS) и применённый Вами МК так (и только так!) выполняет команду MOVX. Что делать, если нужно использовать другие порты? В этом случае сигналы прийдется формировать программным способом (с помощью команд, отличных от MOVX, выводить на нужные порты необходимые сигналы в нужной последовательности и с соблюдением необходимых временных интервалов).
Aleksandr_KPI
Спасибо за пояснение.
Aleksandr_KPI
1. Подскажите почему код выполняет одинаковую временную задержку на частотах микроконтроллера 11 и 22 МГц. Моделирую в Keil uVision.
Код
        DELL_1MS:
        
        MOV     TMP_CNT,#250
        DJNZ    TMP_CNT,$
        MOV     TMP_CNT,#250
        DJNZ    TMP_CNT,$
        RET
        ORG     8000
        JMP     START_PROG


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

Код
ORG     8000
JMP     START_PROG
toweroff
Цитата(Aleksandr_KPI @ Jun 14 2010, 16:09) *
Эта часть кода, когда нибуть выполняется? Перед ней ведь стоит команда RET.

Код
ORG     8000
JMP     START_PROG

директива ORG сообщает компилятору, что следующие инструкции он должен размещать с указанного адреса, в данном случае - с 8000
ViKo
Цитата(Aleksandr_KPI @ Jun 14 2010, 15:09) *
2. Эта часть кода, когда нибуть выполняется? Перед ней ведь стоит команда RET.

Я думаю, программист пытался "подстраховаться", если программный счетчик скакнет куда-нибудь, куда его "не просили", и тогда доберется до перехода на старт. Сомнительная польза...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.