Сейчас на форуме: Dart Raiden, bedop66938, morgot (+6 невидимых)

 eXeL@B —› Электроника —› PIC 16F877 настройка USART
Посл.ответ Сообщение

Ранг: 13.8 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 28 октября 2011 19:34 · Поправил: cosinus
· Личное сообщение · #1

Доброго времени суток форумчане.
Имею код на Cи
Code:
  1. #include <pic.h>
  2. #include "conio.h"
  3. #include "string.h"
  4. #include "stdio.h"
  5. #include "delay.h"
  6. #include "rs232.h"
  7.  
  8. void main()
  9. {
  10.  
  11. // инициализация порта
  12. ADCON0=0;ADCON1=6; // оключает аналоговые входы
  13. TRISA=0b00000000; // всеножки порта на "выход"
  14. TRISE=0b00000100; // порт RE2 используется как вход
  15. RA0=1;
  16. RA1=1;
  17. RA2=1;
  18. RA3=1;
  19. Rs232_Init();
  20.  
  21. // главный цикл
  22. while(1)
  23. {
  24.  
  25. if (!RE2) {RA1=0; RA2=0; RA3=0; printf("Hello World\r\n");}
  26.  
  27. }
  28.  
  29. }//main


Микроконтроллер подлючен к компьютеру через ST232. Так же на порте PORTE на ножке RE2 "висит" кнопка. При нажатии на которую получаю на ножке RE2 ноль, после чего выводится на терминалку "Hello World"
файл rs232.h
Code:
  1. void Rs232_Init   (void);
  2. void Rs232_Put    (char);
  3. //char Rs232_Get  (void);
  4. char Rs232_Get    (char*);
  5.  
  6. #define BSIZE 78
  7. bank1 unsigned char buf[BSIZE]; /* Кольцевой буфер */
  8. unsigned char *inptr = buf; /* Указатель на первое свободное место */
  9. unsigned char *outptr = buf; /* Указатель на первый считываемый байт */
  10.  
  11.  
  12. void interrupt rs232(void)
  13. {
  14. *inptr = RCREG; /* Считаем байт */
  15. if (++inptr >= &buf[BSIZE])     /* Проверка выхода за границу буфера    */
  16.                         inptr = buf; /* Если да, то начнем сначала */
  17. }
  18.  
  19. void Rs232_Init(void)
  20. {
  21.          TRISC7=1;
  22.          TRISC6=1;
  23.          BRGH = 1; /* high baud rate */
  24. //       SPBRG = 25; /* set the baud rate */ //9600
  25.          SPBRG = 129; /* set the baud rate */ //9600
  26. //       SPBRG = 12; /* set the baud rate */ //19200
  27.          SYNC = 0; /* asynchronous */
  28.          SPEN = 1; /* enable serial port pins */
  29.          CREN = 1; /* enable reception */
  30.          SREN = 0; /* no effect */
  31.          TXIE = 0; /* disable tx interrupts */
  32.          RCIE = 1; /* enable rx interrupts*/
  33. //       RCIE = 0; /* disable rx interrupts */
  34.          TX9  = 0; /* 8- or 9-bit transmission */
  35.          RX9  = 0; /* 8- or 9-bit reception */
  36.          TXEN = 1; /* enable the transmitter */
  37. //       PIE1=0x020; /* enable rx interrupts*/
  38. //       INTCON=0x080; /* прерывания разрешены*/
  39.          PEIE=1; /* разрешаем прерывания от переферийных модулей */
  40.          GIE=1; /* глобальное разрешение прерываний*/
  41.          if (OERR) {CREN=0; CREN=1;} // проверка на переполнение буфера и восстановление приёма
  42. }
  43.  
  44. /*
  45. void Rs232_Put(char byte)
  46. {
  47.          while(!TXIF) continue; // дожидаемся освобождения буфера передатчика
  48.          TXREG = byte;
  49. }
  50. */
  51.  
  52. void putch(char byte)
  53. {
  54.          while(!TXIF) continue; // дожидаемся освобождения буфера передатчика
  55.          TXREG = byte;
  56. }
  57.  
  58.  
  59. char Rs232_Get(char * ch)
  60. {
  61. if (inptr != outptr) {         
  62.     *ch = *outptr;
  63.     if (++outptr >= &buf[BSIZE])    
  64.          outptr = buf;
  65.          return(1);
  66.     }
  67. else return(0);
  68. }
  69.  
  70. void Rs232_PutStr(const char *byte)
  71. {while(*byte){while(!TXIF) continue;TXREG = *byte; *byte++;};}


Всё прекрасно работает.
Решил переписать этот код на ассемблере, так как код не мой и в синтаксисе Си я не разбираюсь.
(Этот код мне написали, чтобы заинтересовать в программировании "железных рук" и продемонстрировать работу МК)
Вообщем загружаю hex-файл прошивки в эмулятор ( PIC Simulator IDE ) и обложившись мануалами начал трассировать.
В итоге вот что у меня получилось:
Code:
  1.          
  2.         start:
  3.          bsf STATUS, RP0               ;\_Переходим в банк 1
  4.          bcf STATUS, RP1               ;/
  5.          clrf ADCON1               ;\
  6.          movlw 6h                                ; Отключение АЦП
  7.          movwf ADCON1         ;/
  8.          movlw b'00000100'          ;\_Настраиваем порт RE2 на вход
  9.          movwf TRISE               ;/
  10.          movlw b'11000000'                 ;\__Устанавливаем биты 6 и 7 чтобы работал Rx Tx
  11.          movwf TRISC               ;/
  12.          movlw b'00100110'                 ;TXEN=1h, SYNC=0h, BRGH=1h, TSR=1h
  13.          movwf TXSTA               ;Настраиваем передатчик
  14.                         
  15.          movlw 81h                     ;Помещаем в аккумулятор число 31 (BRGH=0) (129 [81h] при BRGH=1, погрешность 0.16)
  16.          movwf SPBRG               ;Настраиваем USART МК для работы с кварцем на 20 МГц и скорости обмена в 9600 бит/сек.
  17.          movlw b'00100000'                 ;Настраиваем регистр с масками прерываний переферийных устройств
  18.          movwf PIE1                  ;( RCIE=1h ) Разрешаем прерывание от приёмника USART
  19.  
  20.          movlw b'11000000'                 ;Настраиваем регистр флагов и масок прерываний
  21.          movwf INTCON            ;GIE=1h, PEIE=1h
  22.  
  23.  
  24.          bcf STATUS, RP0               ;\_Переходим в банк 0
  25.          bcf STATUS, RP1               ;/
  26.          clrf ADCON0               ;Отключение АЦП
  27.          movlw b'11000000'                 ;Настраиваем регистр флагов и масок прерываний
  28.          movwf INTCON            ;GIE=1h, PEIE=1h
  29.  
  30.          movlw b'10010000'                 ;Настраивем регистр управления и статуса приёмника RCSTA
  31.          movwf RCSTA               ;SPEN=1h, CREN=1h
  32.  
  33. loc_1:
  34. btfss PORTE, RE2        ;Пропустить следующую команду, если на ножке RE2 порта Е "единица"
  35. goto loc_2                   ; При нажатии на "кнопку" получаем "лог.ноль" и выводим на терминал строчку
  36. goto loc_1
  37.  
  38. loc_2:
  39.          call Send_Hello
  40.          goto loc_1
  41.  
  42. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  43. ; Вывести "Hello World"
  44. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  45. Send_Hello
  46. movlw 'H'
  47.  call TX
  48. movlw 'e'
  49.  call TX
  50. movlw 'l'
  51.  call TX
  52. movlw 'l'
  53.  call TX
  54. movlw 'o'
  55.  call TX
  56. movlw 20h         ; пробел
  57.  call TX
  58. movlw 'W'
  59.  call TX
  60. movlw 'o'
  61.  call TX
  62. movlw 'r'
  63.  call TX
  64. movlw 'l'
  65.  call TX
  66. movlw 'd'
  67.  call TX
  68. movlw 0Dh
  69.  call TX
  70. movlw 0Ah
  71.  call TX
  72. return
  73. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  74. ; Функция передачи
  75. ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  76. TX
  77.          movwf TXREG               ; Помещаем в регистр TXREG то, что надо передать.
  78.          bsf STATUS, RP0               ;\_Переходим в банк 1
  79.          bcf STATUS, RP1          ;/
  80. loc_tx:
  81.          btfss TXSTA, TRMT                 ; Ждём пока пик не освободит
  82.          goto loc_tx               ; сдвиговый регистр передатчика
  83.          bcf STATUS, RP0               ;\_Переходим в банк 0
  84.          bcf STATUS, RP1          ;/
  85. return                       ; Выход из процедуры
  86.  
  87.  


После компиляции и "заливки" прошивки, заветная строчка НЕ прилетает на терминалку.
Вот собственно просьба, подскажите где я допустил ошибку? И помогите перевести "СИшный" код в ASM.
Думаю что ошибка в инициализации USART, но тыщу раз просматривал в эмуляторе и никак не могу увидеть.

Конечно код...
Code:
  1.          
  2. movlw b'00100110'          ;TXEN=1h, SYNC=0h, BRGH=1h, TSR=1h
  3. movwf TXSTA                  ;Настраиваем передатчик


... можно представить в виде

Code:
  1. clrf TXSTA
  2. bsf TXSTA, TXEN
  3. bsf TXSTA, BRGH
  4. bsf TXSTA, TSR

Но при трассировке в MPLAB (и на живом железе тоже), команды типа
Code:
  1. clrf PORTA
  2. bsf PORTA, RA0
  3. bsf PORTA, RA1
  4. bsf PORTA, RA2

"взводится" только одна ножка порта (а точнее по очереди), потому и выбран был вышеуказанный способ. Потому как думал это "недочёт" микроконтроллеров и трабла в инициализации USART могла в этих командах.
PS. на ножках RA0-RA2 у меня висят светодиодики, и их я в коде не указал из-за экономии места. И именно для этих светодиодов включено прерывание от приёмника... дабы принять цифру "1" и зажечь светодиод RA0. И также в коде не указан обработчик прерываний (но он есть)

Или быть может у меня дизассемблер неправильно работает, или одно из двух
т.к. строки исходника....
Code:
  1. ADCON0=0;ADCON1=6; // оключает аналоговые входы
  2. TRISA=0b00000000; // всеножки порта на "выход"
  3. TRISE=0b00000100; // порт RE2 используется как вход


...превращаются в
Code:
  1. L13:
  2. clrf 0x1F                  ; Очистить ADCON0 (находится в 0-ом банке)
  3. movlw 0x06            ; Поместить в аккамулятор 6h
  4. bsf STATUS,RP0       ; Перейти в банк 1
  5. movwf 0x1F            ; Переслать содержимое аккамулятора в регистр ADCON0
  6. clrf 0x05                 ; Очистить регистр PORTA
  7. movlw 0x04            ; Поместить в аккамулятор 4h
  8. movwf 0x09            ; Присвоить значение регистру PORTE значение аккамулятора, что в двоичной системе есть "00000100"


То есть по сути всё ровно, только не понятно как находясь в банке 1, можно обращаться к данным в банке 0 ? Ведь регистр ADCON0 находится в 0-ом банке. А так же фигурируют адреса PORTA и PORTE, когда должны быть адреса TRISA (85h)и TRISE(89h). И вообще 6h для ADCON1 предназначено.



Ранг: 13.8 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 29 октября 2011 07:43 · Поправил: cosinus
· Личное сообщение · #2

Разобрался с дизассемблером, оказывается он некорректно работает.
Code:
  1. 0011    019F    L13:       clrf ADCON0
  2. 0012    3006      movlw 0x06
  3. 0013    1683      bsf STATUS,RP0
  4. 0014    009F      movwf 0x1F
  5. 0015    0185      clrf PORTA
  6. 0016    3004      movlw 0x04
  7. 0017    0089      movwf 0x09


Обратив внимание на опкоды, увидел следущее: 0011 019F обозначает стереть регистр, адрес которого 9F чему соответствует ADCON1. Точно также и с командой по адресу 0015:
0185 - которая очищает регистр адрес которого 85h чему соответсвует TRISA, а вовсе не PORTA как показывает дизассемблер. Исшо адресс 0017 определён не верно - опкод 0089 обозначает, что надо переслать число из аккамулятора (WREG) в 89h. А по адресу 89h как раз находится TRISE.



up:
Оказалось что дизассемблер НЕ отслеживает изменения банка памяти, вследствие чего выдаёт такие "недоразумения".



Ранг: 13.8 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 29 октября 2011 23:46
· Личное сообщение · #3

Разобрался с проблемой.
Оказалось, что у меня (в asm-коде) не корректная обработка прерываний. А точнее выход из прерывания с восстановлением WREG и STATUS. Отключив все прерывания (INTCON, PIE\GIE), заветная строчка вывелась на терминал.
Прерывание от приёмника USART было включено. Так как у меня на ножках порта А "висят" светодиоды, и в зависимости от цифры посланной МК - зажигался светодиод. А при нажатии на кнопку (PORTE, RE2) выводилась строка.
Но то что дизассемблеры в MPLAB IDE и в PIC Simulator IDE не отслеживают изменения банка памяти - факт.
Будте осторожны

| Сообщение посчитали полезным: Bad_guy
 eXeL@B —› Электроника —› PIC 16F877 настройка USART
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати