Przeanalizujmy następujący fragment kodu:
LCD_write("Jakis tekst");
Jest to fragment kodu wypisujący na wyświetlaczu LCD tekst. Pomimo że wydaje się to optymalnym rozwiązaniem takim nie jest. Co się powinno dziać w przypadku wywołania takiej funkcji? Funkcja powinna pobierać znak po znaku każdą literę z pamięci programu i wysyłać je do wyświetlacza. Niestety funkcja ta nie odczytuje tekstu z pamięci programu (przypominam FLASH) lecz z pamięci RAM co jest wielką stratą i kosztuje nas cykle pracy układu. Jest jednak sposób na oszczędzenie pamięci. Będziemy korzystać z nagłówka:
#include <avr/pgmspace.h>
Teraz jeżeli chcemy przechowywać łańcuch znaków tylko w pamięci programu napiszemy:
const char string[] PROGMEM = "Ten łańcuch znaków nie może zostać zmieniony i jest przechowywany w pamięci FLASH.";
Lub kożystając z makra możemy wprowadzać łańcuchy wewnątrz kodu:
LCD_write_P(PSTR("Program Memory String"));
Niestety to nie wszystko co trzeba zrobić, zmienna string
oraz makro zwracają adres w pamięci FLASH a nie RAM tak jak jest to oczekiwane przez dotychczas istniejące funkcje. Trzeba je niestety zmodyfikować. Przeanalizujmy następujące fragmenty kodu:
while (*data != '\0') ... while (pgm_read_byte(data) != 0x00)
W przypadku odczytu z pamięci RAM korzystamy z pierwszej pętli natomiast aby odczytać bajt z pamięci programu należy wykorzystać funkcję pgm_read_byte
. Często wyróżnia się funkcje odczytujące z pamięci FLASH kończąc ich nazwę na _P
.
Bardzo dobre opracowanie PROGMEM: AVRFreaks [EN]