Motylowy termometr
Kontroler DMA
Mikrokontrolery STM32F107 wyposażono w 12-kanałowy kontroler DMA. Każdy kanał może mieć programowo przypisany priorytet. Możliwa jest transmisja pomiędzy dwoma urządzeniami peryferyjnymi, z urządzenia peryferyjnego do pamięci, z pamięci do urządzenia peryferyjnego oraz z pamięci do pamięci. Dane można przesyłać od/do pojedynczych adresów, można także przesyłać bloki danych, przy czym maksymalny rozmiar takiego bloku może wynosić 65535 elementów (bajtów, półsłów lub słów).
Fragment programu konfigurującego kontroler DMA do pracy z przetwornikiem A/C przedstawiono na list. 2.
List. 2. Konfiguracja DMA do pracy z przetwornikiem A/C
// Konfiguracja DMA DMA_DeInit(DMA1_Channel1); DMA_InitStruct.DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_InitStruct.DMA_MemoryBaseAddr = (u32)&ADCVal; // Kierunek: zrodlem jest ADC DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; // Rozmiar burora: jeden kanal = rozmiar bufora 1 DMA_InitStruct.DMA_BufferSize = 1; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // Dane beda przesylane ciagle DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStruct); // Wlacz DMA DMA_Cmd(DMA1_Channel1, ENABLE);
Sterowniki wyświetlacza LCD
Na potrzeby aplikacji przygotowano trójwymiarową tablice zawierającą wygląd cyfr o wymiarach 24 na 40 pikseli, co umożliwiło zdefiniowanie czcionki Comic Sans MS o rozmiarze 36 punktów. Oprócz cyfr od 0 do 9 w tablicy znajduje się również znak oC. Fragment tablicy zamieszczono na list. 3.
List. 3. Fragment tablicy definicji znaków o rozmiarze 24 na 40 pikseli
// 24x40 pikseli, czcionka 36 punktow, Comic Sans MS static const char number[11][5][24] = { //0 {{ 0x00 , 0x00 , 0xC0 , 0xF0 , 0xF8 , 0xFC , 0xFE , 0x7E, 0x3F , 0x1F , 0x1F , 0x1F , 0x1F , 0x3F , 0x7F , 0xFE, 0xFC , 0xF8 , 0xE0 , 0xC0 , 0x00 , 0x00 , 0x00 , 0x00 },{ 0xE0 , 0xFF , 0xFF , 0xFF , 0xFF , 0x1F , 0x01 , 0x00, 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01, 0x0F , 0xFF , 0xFF , 0xFF , 0xFF , 0xF8 , 0x00 , 0x00 },{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0x00 , 0x00, 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00, 0x80 , 0xFF , 0xFF , 0xFF , 0xFF , 0x7F , 0x00 , 0x00 },{ 0x00 , 0x3F , 0xFF , 0xFF , 0xFF , 0xFF , 0xF0 , 0x80, 0x80 , 0x00 , 0x00 , 0x00 , 0x80 , 0xC0 , 0xE0 , 0xF8, 0xFF , 0xFF , 0xFF , 0x3F , 0x0F , 0x00 , 0x00 , 0x00 },{ 0x00 , 0x00 , 0x00 , 0x01 , 0x03 , 0x07 , 0x0F , 0x0F, 0x1F , 0x1F , 0x1F , 0x1F , 0x0F , 0x0F , 0x0F , 0x07, 0x03 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 }},
Wyświetlenie znaku z tablicy odbywa się za pomocą wywołania funkcji LCD_WriteChar(). W argumentach należy podać pozycję znaku w tablicy oraz numery wiersza i kolumny (początek rysowania znaku). Ciało funkcji przedstawiono na list. 4.
List. 4. Funkcja rysująca na LCD duże cyfry
void LCD_WriteChar (unsigned char ch, unsigned char col, unsigned char row) { unsigned char i, j; if(ch == 'o') ch = 10; else ch = ch & 0x0f; for(i=0;i<5;i++) { LCD_GotoXY (col, row+i); for(j=0; j<24; j++) { lcd_buffer[cursor_row][cursor_col + j] |= number[ch][i][j]; LCD_WriteData(lcd_buffer[cursor_row][cursor_col + j]); } } }
Spojrzenie na całość
Po zakończeniu konfiguracji mikrokontroler przystępuje do wykonywania pętli while, przedstawionej na list. 5. Wynik pomiaru temperatury po obliczeniach jest przechowywany w zmiennej globalnej temp_a, jest to aktualna wartość temperatury zmierzonej przez czujnik ulokowany w strukturze mikrokontrolera.
List. 5. Główna pętla programu
while(1) { // Odczyt temperatury + obliczenia temp_a = (1430 - ADCVal[0]*0.805) / 4.3 + 25; // Obliczenie sredniej z 256 pomiarow for(avg_cnt=0; avg_cnt>= 8; // Jesli temperatura sie zmienila if(temp_a != temp_p) { // Zapisanie wynikow pomiarow do tablic znakow sprintf(temp_tab, "%d", temp_a); LCD_Clear (); LCD_WriteChar('o', 53, 1); // Znak st C LCD_WriteChar(temp_tab[0], 5, 1); LCD_WriteChar(temp_tab[1], 29, 1); temp_p = temp_a; } }
Dla poprawienia dokładności pomiarów obliczana jest średnia arytmetyczna wyników kolejnych 256 pomiarów. Następnie mikrokontroler sprawdza, czy od ostatniej aktualizacji zawartości wyświetlacza temperatura zmieniła się. Jeśli tak, to zawartość wyświetlacza LCD jest aktualizowana, a wartość aktualnej temperatury jest archiwizowana w zmiennej temp_p.