Aktykuły które nie zmieściły się w żadnej kategorii

0102 /03
04Procesory Atmel megaAVR 0-series.

Algorytmy tu zaprezentowane były testowane na procesorach Atmega4809 lub Attiny1614 przy pomocy środowiska Atmel Studio 7.0. Opisuje konfigurację urządzeń peryferyjnych w tych procesorach.
06
070809

Analizę kodu zacznijmy do main.

W pierwszej linii odblokowujemy dostęp do rejestru MCLKCTRLB tak byśmy mogli w nim dokonać zmian. Procesor domyśle startuje z wewnęntrzym zegarze 20MHz ale dzielonym przez 6 co daje 3.333MHz. Ustawiając ostatni bit rejestru na zero wyłączamy podział i od tej chwili nasz procesor pracuje na 20MHz.

PORTB.DIR ustalamy kierunki pracy poszczególnych pinów w bramie.

Następnie przechodzimy do inicjacji uarta-0.

Domyślnie USART0 jest podłączony do pinów PA0 i PA1

//uart0 na pinach podstawowych
//PORTA.DIRSET = PIN0_bm; // PA0(44)=0.TxD
//PORTA.DIRCLR = PIN1_bm; // PA1(45)=0.RxD

ale ja tutaj pokazuje jak przestawić USART0 na piny alternatywne PA4 i PA5.

// uart na pinach zapasowych
PORTMUX.USARTROUTEA = 0b00000001;
PORTA.DIRSET = PIN4_bm; // PA4(48)=0.TxD
PORTA.DIRCLR = PIN5_bm; // PA5( 1)=0.RxD

Należy zwrócić uwagę że trzeba odpowiednio ustalić kierunki pracy dla poszczególnych sygnałów.

Kolejnym urządzeniem które uruchamiam to jest jedn z timerów, a konkretnie TCA0.
Timer jest tak ustawiony by dawał przerwanie co około 1 sekundy. Przerwanie dla timera zapisujemy w następujący sposób ISR(TCA0_OVF_vect). Istotna różnica między zwykłymi AVR jest to że trzeba kasować flagę przerwania informując procesor że zostało obsłużone. TCA0.SINGLE.INTFLAGS = ( TCA_SINGLE_OVF_bm); Jak tego nie dokonamy w obsłudze przerwania to procesor uparcie będzie je wykonywał w kółko. Dotyczy to również innych przerwań.

  1. /*
  2.  *       Created: 2019-07-30 22:35:28
  3.  *       Author : Dasej
  4.  */ 
  5. #define F_CPU 20000000
  6. #include <avr/io.h>
  7. #include <util/delay.h>
  8. #include <avr/interrupt.h>
  9. #include <string.h>
  10. #include <stdlib.h>  // ltoa  konwersja liczb
  11. uint16_t sekunda = 0;
  12. #define USART0_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)
  13. void USART0_init(void)
  14. {   
  15.   // inicjacja i obsługa uarta0
  16.   // 115200 8 N 1
  17.   //uart0 na pinach podstawowych  
  18.   //PORTA.DIRSET = PIN0_bm; // PA0(44)=0.TxD
  19.   //PORTA.DIRCLR = PIN1_bm; // PA1(45)=0.RxD
  20.   // uart na pinach zapasowych
  21.   PORTMUX.USARTROUTEA = 0b00000001;
  22.   PORTA.DIRSET = PIN4_bm; // PA4(48)=0.TxD
  23.   PORTA.DIRCLR = PIN5_bm; // PA5( 1)=0.RxD
  24.   USART0.BAUD = (uint16_t)USART0_BAUD_RATE(115200);
  25.   USART0.CTRLB |= USART_TXEN_bm;
  26. }
  27. void USART0_sendChar(char c)
  28. {
  29.   while (!(USART0.STATUS & USART_DREIF_bm)) {;}
  30.   USART0.TXDATAL = c;
  31. }
  32. void USART0_sendString(char *str)
  33. {
  34.   for(size_t i = 0; i < strlen(str); i++)
  35.     { USART0_sendChar(str[i]); }
  36. }
  37. void rsInt0( long num ) // wysłanie liczby całkowitej
  38. {
  39.    char buffer[81];
  40.    ltoa( num , buffer, 10);
  41.    USART0_sendString ( buffer );
  42. }
  43. ISR(TCA0_OVF_vect)
  44. {
  45.   // kasowanie znacznika przerwania jak nie zostanie 
  46.   // zkasowany to przerwanie będzie stale się wywołyłało 
  47.   TCA0.SINGLE.INTFLAGS = ( TCA_SINGLE_OVF_bm);
  48.   // informacja że przerwanie zostało wykonane 
  49.   PORTB.OUTTGL =  PIN4_bm | PIN0_bm;
  50.   USART0_sendString("T.");
  51. }
  52. void initTimer(void)
  53. {
  54.   TCA0.SINGLE.CTRLA =  0b00001111; // prescaler 1024 i b0 = enable włącz timer
  55.   TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
  56.   // TCA0.SINGLE.PER = (20 000 000 / prescaler 1024) co daje
  57.   TCA0.SINGLE.PER = 0x4C4B; //  przerwanie co 1 sekundę 
  58. }
  59. ISR(RTC_CNT_vect)
  60. {
  61.   RTC.INTFLAGS = RTC_OVF_bm;
  62.   sekunda++;
  63. }
  64. void initRTC(void)
  65. {
  66.   RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;
  67.   while (RTC.STATUS>0); // czekaj na ustabilizowanie zagara
  68.   RTC.CTRLA = RTC_PRESCALER_DIV32_gc | RTC_RTCEN_bm | RTC_RUNSTDBY_bm;
  69.   RTC.PER = 1024; // zegar ( 32768 / 32 ) / 1024 = 1 sekunda  
  70.   RTC.INTCTRL |= RTC_OVF_bm;
  71. }
  72. int main(void)
  73. {
  74.   CPU_CCP = CCP_IOREG_gc;  // odblokowanie zapisu do rejestru MCLKCTRLB
  75.   CLKCTRL.MCLKCTRLB = 0x10; // wyłacz podział CLKCTRL_PEN_bp 
  76.   PORTB.DIR = PIN4_bm | PIN0_bm;
  77.   USART0_init();
  78.   initTimer();
  79.   USART0_sendString("Start uart\r\n");
  80.   initRTC();
  81.   sei();
  82.   while (1)
  83.     {
  84.       USART0_sendString("Hello World! : sekunda= ");
  85.       rsInt0(sekunda);
  86.       USART0_sendString("\n\r");
  87.       _delay_ms(1000);
  88.     }    
  89. }

W plikach nagłówkowych procesorów Atmel dodał litery za nazwami rejestrów lub opisu poszczególnych bitów rejestru. Litery których znaczenie widać w poniższym oknie kodu.

  1. ..._gm 0x03   - maska
  2. ..._gp 0      - pozycja
  3. ..._bm (1<<0) - bit maski
  4. ..._bp 0      - bit pozycja
  5. // fragment kodu z pliku iom4809.h
  6. // CRCSCAN.CTRLB  bit masks and bit positions
  7. #define CRCSCAN_SRC_gm  0x03  // CRC Source group mask. 
  8. #define CRCSCAN_SRC_gp  0  // CRC Source group position.
  9. #define CRCSCAN_SRC0_bm  (1<<0)  // CRC Source bit 0 mask. 
  10. #define CRCSCAN_SRC0_bp  0  // CRC Source bit 0 position. 
  11. #define CRCSCAN_SRC1_bm  (1<<1)  // CRC Source bit 1 mask.
  12. #define CRCSCAN_SRC1_bp  1  // CRC Source bit 1 position.
  13. #define CRCSCAN_MODE_gm  0x30  // CRC Flash Access Mode group mask.
  14. #define CRCSCAN_MODE_gp  4  // CRC Flash Access Mode group position.
  15. #define CRCSCAN_MODE0_bm  (1<<4)  // CRC Flash Access Mode bit 0 mask.
  16. #define CRCSCAN_MODE0_bp  4  // CRC Flash Access Mode bit 0 position.
  17. #define CRCSCAN_MODE1_bm  (1<<5)  // CRC Flash Access Mode bit 1 mask.
  18. #define CRCSCAN_MODE1_bp  5  // CRC Flash Access Mode bit 1 position.

Licznik TCB jest prostszą wersją licznika TCA. Licznika TCB0 z uruchomionym przerwaniem. Wywołujący przerwanie na zasadzie porównania rejestru TCB0.CNT ( licznika ) z rejestrem TCB0.CCMP W odniesieniu do zwykłych liczników w AVR-erach można użyć określenia ( przerwanie wywołanie przepełnieniem licznika ).

  1. ISR(TCB0_INT_vect)
  2. {
  3. TCB0.INTFLAGS = TCB_CAPT_bm; // kasowanie flagi, wymagane
  4. razy++;
  5. }
  6. void start(void)
  7. {
  8. razy =0; // ile przerwań 
  9. TCB0.INTCTRL =1; // uruchom przerwanie
  10. TCB0.CCMP = 0xFFFF; // porównie do 
  11. TCB0.CNT = 0;  // licznik 
  12. TCB0.CTRLA = 1; // włącz timer / taktowanie procesora
  13. }
  14. void stop(void)
  15. {
  16. TCB0.CTRLA = 0; // wyłącz timer
  17. }

Kilka informacji o konfigurowaniu PORT-ów.

  1.     PORTC.DIR = 0b00001111   // ustawienie całego portu jednoczesnie
  2.     PORTC.DIRSET = 0xF0; // ustaw tylko bity 7,6,5,4
  3.     PORTC.DIRCLR = 0x60; // skazuj tylko bity 6,5
  4.     PORTC.DIRTGL = 0x06; // odwróc znacznie tylko bitów 2,1 
  5.     PORTC.DIR = 0xFF   // ustawienie całego portu jednoczesnie
  6.     PORTC.OUT = 0b01010101;  
  7.     PORTC.OUTSET = 0b10;
  8.     PORTC.OUTSET = (1<<3)|(1<<7); // zamiennie PORTC.OUT |= (1<<3)|(1<<7); 
  9.     PORTC.OUTSET = PIN5_bm; // zamienna operacji PORTC.OUT |= (1<<5); 
  10.     PORTC.OUT = 0;  
  11.     PORTC.OUT |= 5; 
  12.     PORTC.OUT = 0;  
  13.     PORTC.OUTSET = PIN5_bp; // zamienna operacji PORTC.OUT |= 5; 
  14.     PORTC.DIR = 0b11011111   
  15. //    PORTC.OUTTGL;
  16. //    PORTC.IN;  
  17. //    PORTC.INTFLAGS; 
  18. //    PORTC.PORTCTRL; 
  19. /* PINxCTRL 
  20.     bit 7 = inwerter pinu w bramie
  21.     bit 3 = podciągnij pin do zasilanie przez rezystor
  22.     bit 2,1,0 = przerwania
  23.     0x0 INTDISABLE     Przerwanie wyłączone, ale bufor wejściowy włączony
  24.     0x1 BOTHEDGES      Przerwanie włączone z wyczuciem w obu krawędziach
  25.     0x2 RISING         Przerwanie włączone z wyczuciem na zbocze narastające
  26.     0x3 FALLING        Przerwanie włączone z wyczuciem na zbocze opadające
  27.     0x4 INPUT_DISABLE  Przerwanie i bufor wejścia cyfrowego wyłączony
  28.     0x5 POZIOM POZIOMU włączony z wyczuciem na niskim poziomie
  29.     PORTD interrupt vectors 
  30.     #define PORTD_PORT_vect_num  20
  31.     #define PORTD_PORT_vect      _VECTOR(20)  a
  32. */
  33.     PORTC.PIN0CTRL; 
  34.     PORTC.PIN1CTRL; 
  35.     PORTC.PIN2CTRL; 
  36.     PORTC.PIN3CTRL; 
  37.     PORTC.PIN4CTRL; 
  38.     PORTC.PIN5CTRL = 2; // zbocze narastające
  39.     PORTC.PIN6CTRL; 
  40.     PORTC.PIN7CTRL; 
0102 /03
04Obsługa przerwania od PORT-u. Należy zwrócić uwagę że obsługa przewanie jest wywoływane dla całego portu a nie wybranego pinu w porcie. Pierwsze co musimy zrobić to sprawdzić który pin zgłosił przerwanie. Chyba że mamy ustawiony tylko jeden pin w porcie który będzie zgłaszał przerwanie. 06
070809
  1. ISR(PORTC_PORT_vect)
  2. {
  3.     if(PORTC.INTFLAGS & PIN5_bm) // sprawdzenie czy 5 bit wywołał przerwanie
  4.       { 
  5.          PORTC.OUTSET = PIN7_bm;
  6.       }
  7.     PORTC.INTFLAGS |=  PIN5_bm;   // kasowanie flagi przerwania, wymagane
  8. }



Dasej (C) 2019 : 4223