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. }



Kilka procedur do wysyłania danych przez USART.
  1. void initUsart0(float bspeed)
  2. {
  3.     // 115200 reszt 8 N 1 danych jest ustawiona domyslnie danych jest
  4.     //uart0 na pinach podstawowych
  5.     PORTB.DIRSET = PIN2_bm; // PA0(44)=0.TxD
  6.     PORTB.DIRCLR = PIN3_bm; // PA1(45)=0.RxD
  7.     // uart na pinach zapasowych
  8.     //PORTMUX.USARTROUTEA = 0b00000001;
  9.     //PORTA.DIRSET = PIN4_bm; // PA4(48)=0.TxD
  10.     //PORTA.DIRCLR = PIN5_bm; // PA5( 1)=0.RxD
  11.    
  12.     USART0.BAUD = (uint16_t)USART0_BAUD_RATE(bspeed);
  13.     USART0.CTRLB |= USART_TXEN_bm;
  14. }
  15. void rsChar(uint8_t channel ,  char c)
  16. {
  17.     switch (channel)
  18.       {
  19.         case 0 : { while (!(USART0.STATUS & USART_DREIF_bm)); 
  20.                    // bufor USART0.TXDATAL jest pusty
  21.                    USART0.STATUS |= USART_TXCIF_bm;           
  22.                    // flaga informująca o braku danych do wysłania
  23.                    USART0.TXDATAL = c;                        
  24.                    // załadowane nowej danej
  25.                    break; }
  26.         case 1 : { while (!(USART1.STATUS & USART_DREIF_bm));
  27.                    USART1.STATUS |= USART_TXCIF_bm;        
  28.                    USART1.TXDATAL = c; 
  29.                    break; }
  30.         case 2 : { while (!(USART2.STATUS & USART_DREIF_bm));
  31.                    USART2.STATUS |= USART_TXCIF_bm;        
  32.                    USART2.TXDATAL = c; 
  33.                    break; }
  34.         case 3 : { while (!(USART3.STATUS & USART_DREIF_bm));
  35.                    USART3.STATUS |= USART_TXCIF_bm;        
  36.                    USART3.TXDATAL = c; 
  37.                    break }
  38.       }
  39. }
  40. void rsString(uint8_t channel, char *str)
  41. {
  42.     uint8_t i;
  43.     for( i = 0; i < strlen(str); i++)
  44.       { 
  45.         rsChar( channel, str[i]);
  46.       }
  47. }
  48. void rsInt(uint8_t channel, long num ) // wysłanie liczby całkowitej
  49. {
  50.     char buffer[20];
  51.     ltoa( num , buffer, 10);
  52.     rsString(channel, buffer );
  53. }
Procedury i funkcje do obsługi TWI.
  1. /*
  2.  *  twi.c
  3.  *  Created: 2019-08-20
  4.  *  Author: Dasej
  5.  */ 
  6. #include <avr/io.h>
  7. #define TWI0_BAUD(F_SCL)  ((((float)F_CPU / (float)F_SCL)) - 10 )
  8. void initTwi(float ispeed)
  9. {
  10.    TWI0.MBAUD = (uint8_t)TWI0_BAUD(ispeed);  
  11.    TWI0.MCTRLB |= TWI_FLUSH_bm;
  12.    TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm);
  13.    TWI0.MCTRLA = 1<<TWI_SMEN_bp | 1 << TWI_ENABLE_bp;
  14.    TWI0.MSTATUS |= TWI_BUSSTATE_IDLE_gc;
  15. }
  16. void twi_start(char addr)
  17. {
  18.    TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);
  19.    TWI0.MADDR = addr;
  20.    if (addr & 1) { while (!(TWI0_MSTATUS & TWI_RIF_bm)); }
  21.             else { while (!(TWI0_MSTATUS & TWI_WIF_bm)); }
  22. }
  23. char twi_read( char ack)
  24. {
  25.    while (!(TWI0.MSTATUS & TWI_RIF_bm));
  26.    if (ack) { TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp); } //Send ACK
  27.        else { TWI0.MCTRLB |= 1<<TWI_ACKACT_bp;  }  //Send NACK
  28.    return TWI0.MDATA;
  29. }
  30. void twi_write(char data)
  31. {
  32.    while (!((TWI0.MSTATUS & TWI_WIF_bm) | (TWI0_MSTATUS & TWI_RXACK_bm)));
  33.    TWI0.MDATA = data;
  34. }
  35. void twi_stop()
  36. {
  37.    TWI0.MCTRLB |= TWI_MCMD_STOP_gc;
  38. }
Przykład użycia procedur i funkcje do obsługi TWI.
  1.     initTwi(100000);
  2.     // zapis danych do rejestru 
  3.     twi_start(0x90);       // adres urządznie
  4.     twi_write(0x01);       // adres rejestru
  5.     twi_write(0b11100001); // wartość
  6.     twi_stop();
  7.     // odczyt dwóch bajtów 
  8.     twi_start(0x90);  // adres urządznie
  9.     twi_write(0x00);  // adres rejestru do odczytu
  10.     twi_start(0x91);  // adres urządzenia, odczytujemy  
  11.     d1=twi_read(1);   // czytaj dalej 
  12.     d2=twi_read(0);   // zakończ czytanie
  13.     twi_stop();
Odczyt danych z przetwornika ADC0.
  1. /*
  2.  *  ADC.c
  3.  *  Created: 2019-08-17 08:37:35
  4.  *  Author: Dasej
  5.      VREF_ADC0REFSEL_0V55_gc = (0x00<<4),  // Voltage reference at 0.55V
  6.      VREF_ADC0REFSEL_1V1_gc  = (0x01<<4),  // Voltage reference at 1.1V 
  7.      VREF_ADC0REFSEL_2V5_gc  = (0x02<<4),  // Voltage reference at 2.5V 
  8.      VREF_ADC0REFSEL_4V34_gc = (0x03<<4),  // Voltage reference at 4.34V 
  9.      VREF_ADC0REFSEL_1V5_gc  = (0x04<<4),  // Voltage reference at 1.5V 
  10.  
  11.  */ 
  12. #include <avr/io.h>
  13. void initADC(void)
  14. {
  15.     VREF.CTRLA |=( VREF_ADC0REFSEL_2V5_gc);
  16.     ADC0.CTRLA |= ADC_RESSEL_10BIT_gc;
  17.     ADC0.CTRLC |= ADC_PRESC_DIV4_gc;
  18.     ADC0.CTRLC |= ADC_REFSEL_VREFA_gc;
  19.     ADC0.CTRLC |= ADC_SAMPCAP_bm;
  20. }
  21. uint16_t inADC(uint8_t channel)
  22. {
  23.     ADC0_MUXPOS = channel;
  24.     ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc 
  25.     ADC0.CTRLA = ADC_ENABLE_bm;
  26.     ADC0.COMMAND = ADC_STCONV_bm 
  27.     while(!(ADC0.INTFLAGS & ADC_RESRDY_bm)) {;}
  28.     return ADC0.RES;
  29. }



Dasej (C) 2019 : 4570