Mając już oprogramowane diody i przyciski chcielibyśmy, aby nasze urządzenie stało się bardziej interaktywne. Do tego celu służą różnego typu wyświetlacze graficzne i alfanumeryczne. W tym artykule opiszę jak oprogramować standardowy wyświetlacz alfanumeryczny HD44780 dla zestawu ZL29ARM. Aby tego dokonać należy przełączyć zworkę JP3 z GRAPH na CHAR, a następnie włożyć nasz wyświetlacz w miejsce Dist1. Po takiej operacji nasz wyświetlacz będzie podłączony do PE0-10 jak to wynika z noty katalogowej naszego zestawu.
Oczywiście, żeby ułatwić sobie pracę ściągnąłem bibliotek dla danego typu wyświetlacza ze strony http://www.mikrokontroler.pl/content/STMCC . Bibliotek standardowych do tego typu wyświetlacza jest masa w internecie. Wystarczy tylko poszukać. Najlepiej ściągać materiały z helionu, albo marginesu dla książek, ponieważ z reguły mają niezłe komentarze. Oczywiście zachęcam do czytania książek, bo wtedy wiemy dużo więcej o samym sposobie działa danego urządzenia.
Przykład który zaprezentuje jest prostym menu. Wystarczy wgrać bibliotekę do katalogu głównego src i zaincludować ją tak jak to zaprezentowałem w kodzie. Jest to zmodyfikowany kod (dla naszego zestawu ZL29ARM) opisany w książce STM32. Aplikacje i ćwiczenia w języku C. Autor zastosował sprytne rozwiązanie zmiany pinu GPIO_WriteBit(GPIOE, GPIO_Pin_14, (BitAction) (1-GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_14))); Czytamy wartość pinu i odejmujemy ją od jedynki w taki sposób zawsze dostajemy wartość przeciwną.
Biblioteki można pobrać tu kliknij tu aby pobrać :

Autor tej biblioteki dał możliwość zapisywania własnych znaków do wyświetlacza, tak jak to można zauważyć na powyższym obrazku. Aby tego dokonać trzeba zapisać szesnastkowo, które bity mają zostać włączone podając 8 kolejnych liczby do tablicy. Czyli jeśli chcielibyśmy zrobić rysunek diabła należałoby wpisać takie liczby:

Każde następne liczby będą traktowane jako definicja następnego znaku tak jak to zaprezentowano w poniższym kodzie.
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_flash.h>
#include "misc.h"
#include "lcd_hd44780_lib.h"
const unsigned char znakiDodatkowe[32] = {0x0E,0x11,0x1B,0x11,0x11,0x0A,0x0E,0, //alien
0x0A,0x0E,0x11,0x1B,0x11,0x11,0x0A,0x0E, //diabel
0x0E,0x11,0x1B,0x11,0x11,0x0A,0x0E,0x0A, //brodacz
0x1F,0x0A,0x0A,0x04,0x0E,0x0E,0x1F,0}; //klepsydra
//enum bool {False=0, True=1};
void RCC_Config(void);
void GPIO_Config(void);
void NVIC_Config(void);
int main(void)
{
//konfiguracja systemu
RCC_Config();
GPIO_Config();
NVIC_Config();
/*Tu nalezy umiescic ewentualne dalsze funkcje konfigurujace system*/
LCD_Initialize();
LCD_SetUserChar(1, 4, znakiDodatkowe); //zarejestruj dodatkowe znaki
LCD_WriteCommand(HD44780_CLEAR);
unsigned char znak=1;
LCD_WriteTextXY(&znak,1,0);
znak=2;
LCD_WriteTextXY(&znak,2,0);
znak=3;
LCD_WriteTextXY(&znak,3,0);
znak=4;
LCD_WriteTextXY(&znak,4,0);
while (1) {
};
return 0;
}
void NVIC_Config(void)
{
//Konfigurowanie kontrolera przerwan NVIC
#ifdef VECT_TAB_RAM
// Jezeli tablica wektorow w RAM, to ustaw jej adres na 0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else // VECT_TAB_FLASH
// W przeciwnym wypadku ustaw na 0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
void RCC_Config(void)
{
ErrorStatus HSEStartUpStatus;
// Reset ustawien RCC
RCC_DeInit();
// Wlacz HSE
RCC_HSEConfig(RCC_HSE_ON);
// Czekaj za HSE bedzie gotowy
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// zwloka dla pamieci Flash
FLASH_SetLatency(FLASH_Latency_2);
// HCLK = SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// PCLK2 = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);
// PCLK1 = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);
// PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
// Wlacz PLL
RCC_PLLCmd(ENABLE);
// Czekaj az PLL poprawnie sie uruchomi
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// PLL bedzie zrodlem sygnalu zegarowego
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// Czekaj az PLL bedzie sygnalem zegarowym systemu
while(RCC_GetSYSCLKSource() != 0x08);
}
}
void GPIO_Config(void)
{
//konfigurowanie portow GPIO
GPIO_InitTypeDef GPIO_InitStructure;
/*Tu nalezy umiescic kod zwiazany z konfiguracja sygnalow zegarowych potrzebnych w programie peryferiow*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//wlacz taktowanie portu GPIO E
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//wlacz taktowanie portu GPIO C
}
Poniższy kod prezentuje proste menu, które wywołuje określona funkcję. W naszym przypadku jest to naprzemienne zgaszanie i zapalanie diody:
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_flash.h>
#include "misc.h"
#include "lcd_hd44780_lib.h"
#include <stdio.h>
//enum bool {False=0, True=1};
void RCC_Config(void);
void GPIO_Config(void);
void NVIC_Config(void);
void Opcja1(void);
void Opcja2(void);
void Opcja3(void);
int main(void)
{
volatile unsigned int i;
unsigned int pozycja=1;
unsigned char *menu[8] = {"Dioda 1\0","Dioda 2\0","buzze\0"};
//konfiguracja systemu
RCC_Config();
GPIO_Config();
NVIC_Config();
/*Tu nalezy umiescic ewentualne dalsze funkcje konfigurujace system*/
GPIO_ResetBits(GPIOE, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
LCD_Initialize();
LCD_WriteCommand(HD44780_CLEAR);
LCD_WriteText("> \0");
LCD_WriteText(menu[pozycja-1]);
LCD_WriteText(" <\0");
LCD_WriteTextXY(menu[pozycja-1+1],2,1);
while (1) {
if (!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_6) && (pozycja<3)) {
pozycja++;
LCD_WriteCommand(HD44780_CLEAR); //umieszczenie wyswietlania w tym miejscu usuwa problem "migotania" LCD
LCD_WriteText("> \0"); //poniewaz jest odswiwezane tylko wtedy, gdy jest zmiana pozycji, a nie bez przerwy
LCD_WriteText(menu[pozycja-1]);
LCD_WriteText(" <\0");
if (pozycja<3){
LCD_WriteTextXY(menu[pozycja-1+1],2,1);
}
}
if (!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5) && (pozycja>1)) {
pozycja--;
LCD_WriteCommand(HD44780_CLEAR);
LCD_WriteText("> \0");
LCD_WriteText(menu[pozycja-1]);
LCD_WriteText(" <\0");
if (pozycja<3){
LCD_WriteTextXY(menu[pozycja-1+1],2,1);
}
}
if (!GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9)){
switch (pozycja){
case 1: Opcja1(); break;
case 2: Opcja2(); break;
case 3: Opcja3(); break;
default: Opcja1(); break;
}
}
for (i=0; i<1000000ul; i++);
};
return 0;
}
void NVIC_Config(void)
{
//Konfigurowanie kontrolera przerwan NVIC
#ifdef VECT_TAB_RAM
// Jezeli tablica wektorow w RAM, to ustaw jej adres na 0x20000000
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else // VECT_TAB_FLASH
// W przeciwnym wypadku ustaw na 0x08000000
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
void RCC_Config(void)
{
ErrorStatus HSEStartUpStatus;
// Reset ustawien RCC
RCC_DeInit();
// Wlacz HSE
RCC_HSEConfig(RCC_HSE_ON);
// Czekaj za HSE bedzie gotowy
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
// zwloka dla pamieci Flash
FLASH_SetLatency(FLASH_Latency_2);
// HCLK = SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// PCLK2 = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);
// PCLK1 = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);
// PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
// Wlacz PLL
RCC_PLLCmd(ENABLE);
// Czekaj az PLL poprawnie sie uruchomi
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// PLL bedzie zrodlem sygnalu zegarowego
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// Czekaj az PLL bedzie sygnalem zegarowym systemu
while(RCC_GetSYSCLKSource() != 0x08);
}
}
void GPIO_Config(void)
{
//konfigurowanie portow GPIO
GPIO_InitTypeDef GPIO_InitStructure;
/*Tu nalezy umiescic kod zwiazany z konfiguracja sygnalow zegarowych potrzebnych w programie peryferiow*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//wlacz taktowanie portu GPIO E
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//wlacz taktowanie portu GPIO C
/*Tu nalezy umiescic kod zwiazany z konfiguracja poszczegolnych portow GPIO potrzebnych w programie*/
//port B - diody LED
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
//port C - Joystick
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void Opcja1(void){
GPIO_WriteBit(GPIOE, GPIO_Pin_14, (BitAction) (1-GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_14)));
}
void Opcja2(void){
GPIO_WriteBit(GPIOE, GPIO_Pin_15, (BitAction) (1-GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_15)));
}
void Opcja3(void){
GPIO_WriteBit(GPIOE, GPIO_Pin_13, (BitAction) (1-GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_13)));
}
|