Skocz do zawartości

Tworzenie prostego menu na lcd


Krawi92

Pomocna odpowiedź

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Troszkę odświeżę temat, ponieważ znalazłem fajny art nt. tworzenia menu na listach dwukierunkowych. Mniej więcej rozumiem temat, chociaż jeszcze przyda się kilka razy przeczytać, przeanalizować funkcje itp... Tylko problem polega na tym, że nie wiem jak z tego skorzystać 😄 Jak to wg wyświetlić na LCD ? Trochę to może głupio brzmi, ale jakoś nie mogę tego ogarnąć 😛 

Plik .h

/*
 * Author: £ukasz £aguna
 * E-mail: kontakt@embeddedev.pl
 * Blog:   www.EmbeddedDev.pl
 *
 * LCD HD44780 MENU
 * Tutorial(in polish): http://www.embeddeddev.pl/menu-lcd-implementacja/
 *
 * MCU: STM32F103
 *
 */

#ifndef MENU_H_
#define MENU_H_

typedef struct menu_struct menu_t;

struct menu_struct {

	const char * name;
	menu_t * next;
	menu_t * prev;
	menu_t * child;
	menu_t * parent;
	void (*menu_function)(void);

};

menu_t menu1;
	menu_t sub_menu1_1;
		menu_t sub_menu1_1_1;
	menu_t sub_menu1_2;
menu_t menu2;
	menu_t sub_menu2_1;
	menu_t sub_menu2_2;
		menu_t sub_menu2_2_1, sub_menu2_2_2, sub_menu2_2_3, sub_menu2_2_4, sub_menu2_2_5;
	menu_t sub_menu2_3;
	menu_t sub_menu2_4;
	menu_t sub_menu2_5;
menu_t menu3;
menu_t menu4;
menu_t menu5;
menu_t menu6;

void menu_refresh(void);
void menu_next(void);
void menu_prev(void);
void menu_enter(void);
void menu_back(void);

#endif /* MENU_H_ */

plik.c

/*
 * Author: £ukasz £aguna
 * E-mail: kontakt@embeddedev.pl
 * Blog:   www.EmbeddedDev.pl
 *
 * LCD HD44780 MENU
 * Tutorial(in polish): http://www.embeddeddev.pl/menu-lcd-implementacja/
 *
 * MCU: STM32F103
 *
 */

#include <string.h>

#include "../LCD/lcd.h"
#include "../LCD/lcd_buf.h"

#include "menu.h"

// definition of menu's components: (*name, *next, *prev, *child, *parent, (*menu_function))
menu_t menu1 = { "ELEMENT 1", &menu2, &menu6, &sub_menu1_1, NULL, NULL };
	menu_t sub_menu1_1 = { "ELEMENT 1_1", &sub_menu1_2, &sub_menu1_2, &sub_menu1_1_1, &menu1, NULL };
		menu_t sub_menu1_1_1 = { "ELEMENT 1_1_1", NULL, &sub_menu1_1_1, NULL, &sub_menu1_1, NULL };
	menu_t sub_menu1_2 = { "ELEMENT 1_2", NULL, &sub_menu1_1, NULL, &menu1, NULL };
menu_t menu2 = { "ELEMENT 2", &menu3, &menu1, &sub_menu2_1, NULL, NULL };
	menu_t sub_menu2_1 = { "ELEMENT 2_1", &sub_menu2_2, &sub_menu2_4, NULL, &menu2, NULL };
	menu_t sub_menu2_2 = { "ELEMENT 2_2", &sub_menu2_3, &sub_menu2_1, &sub_menu2_2_1, &menu2, NULL };
		menu_t sub_menu2_2_1 = { "ELEMENT 2_2_1", &sub_menu2_2_2, &sub_menu2_2_5, NULL, &sub_menu2_2, NULL };
		menu_t sub_menu2_2_2 = { "ELEMENT 2_2_2", &sub_menu2_2_3, &sub_menu2_2_1, NULL, &sub_menu2_2, NULL };
		menu_t sub_menu2_2_3 = { "ELEMENT 2_2_3", &sub_menu2_2_4, &sub_menu2_2_2, NULL, &sub_menu2_2, NULL };
		menu_t sub_menu2_2_4 = { "ELEMENT 2_2_4", &sub_menu2_2_5, &sub_menu2_2_3, NULL, &sub_menu2_2, NULL };
		menu_t sub_menu2_2_5 = { "ELEMENT 2_2_5", NULL, &sub_menu2_2_4, NULL, &sub_menu2_2, NULL };
	menu_t sub_menu2_3 = { "ELEMENT 2_3", &sub_menu2_4, &sub_menu2_2, NULL, &menu2, NULL };
	menu_t sub_menu2_4 = { "ELEMENT 2_4", NULL, &sub_menu2_3, NULL, &menu2, NULL };
menu_t menu3 = { "ELEMENT 3", &menu4, &menu2, NULL, NULL, NULL };
menu_t menu4 = { "ELEMENT 4", &menu5, &menu3, NULL, NULL, NULL };
menu_t menu5 = { "ELEMENT 5", &menu6, &menu4, NULL, NULL, NULL };
menu_t menu6 = { "ELEMENT 6", NULL, &menu5, NULL, NULL, NULL };

menu_t *currentPointer = &menu1;

uint8_t menu_index;
uint8_t lcd_row_pos;
uint8_t lcd_row_pos_level_1, lcd_row_pos_level_2;

void menu_refresh(void) {

	menu_t *temp;
	uint8_t i;

	if (currentPointer->parent) temp = (currentPointer->parent)->child;
	else temp = &menu1;

	for (i = 0; i != menu_index - lcd_row_pos; i++) {
		temp = temp->next;
	}

	buf_clear();
	for (i = 0; i < LCD_ROWS; i++) {

		buf_locate(0, i);
		if (temp == currentPointer) buf_char(62);
		else buf_char(' ');

		buf_locate(2, i);
		buf_str(temp->name);

		temp = temp->next;
		if (!temp) break;

	}

	// lcd_refresh();
}

uint8_t menu_get_index(menu_t *q) {

	menu_t *temp;
	uint8_t i = 0;

	if (q->parent) temp = (q->parent)->child;
	else temp = &menu1;

	while (temp != q) {
		temp = temp->next;
		i++;
	}

	return i;
}

uint8_t menu_get_level(menu_t *q) {

	menu_t *temp = q;
	uint8_t i = 0;

	if (!q->parent) return 0;

	while (temp->parent != NULL) {
		temp = temp->parent;
		i++;
	}

	return i;
}

void menu_next(void) {

	if (currentPointer->next)
	{

		currentPointer = (*currentPointer).next;
		menu_index++;
		if (++lcd_row_pos > LCD_ROWS - 1) lcd_row_pos = LCD_ROWS - 1;
	}
	else
	{
		menu_index = 0;
		lcd_row_pos = 0;

		if (currentPointer->parent) currentPointer = (currentPointer->parent)->child;
		else currentPointer = &menu1;
	}

	menu_refresh();

}

void menu_prev(void) {

	currentPointer = currentPointer->prev;

	if (menu_index)
	{
		menu_index--;
		if (lcd_row_pos > 0) lcd_row_pos--;
	}
	else
	{
		menu_index = menu_get_index(currentPointer);

		if (menu_index >= LCD_ROWS - 1) lcd_row_pos = LCD_ROWS - 1;
		else lcd_row_pos = menu_index;
	}

	menu_refresh();
}

void menu_enter(void) {

	if (currentPointer->menu_function) currentPointer->menu_function();

	if (currentPointer->child)
	{

		switch (menu_get_level(currentPointer)) {
			case 0:
				lcd_row_pos_level_1 = lcd_row_pos;
				break;

			case 1:
				lcd_row_pos_level_2 = lcd_row_pos;
				break;
		}

		// switch...case can be replaced by:
		// lcd_row_pos_level[ menu_get_level(currentPointer) ] = lcd_row_pos;

		menu_index = 0;
		lcd_row_pos = 0;

		currentPointer = currentPointer->child;

		menu_refresh();
	}
}

void menu_back(void) {

	if (currentPointer->parent) {

		switch (menu_get_level(currentPointer)) {
			case 1:
				lcd_row_pos = lcd_row_pos_level_1;
				break;

			case 2:
				lcd_row_pos = lcd_row_pos_level_2;
				break;
			}

		currentPointer = currentPointer->parent;
		menu_index = menu_get_index(currentPointer);

		menu_refresh();

	}
}

źródło : http://www.embeddeddev.pl/menu-lcd-implementacja/

Link do komentarza
Share on other sites

Odświeżając wątek, staram się analizować kod elvisa, który w sumie wydaję się prosty, ale przerzucenie tego na LCD sprawia mi trochę problemów. Na razie posklejałem trochę kodu, udało mi się wyświetlić 4 elementy powiedzmy menu, no i znacznik, którym mogę sterować za pomocą przycisków góra/dół. 

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "lcd.h"

#define PREV PD0
#define OK PD6
#define UP PD5
#define DOWN PD7

void Rs232_fun(void);
void PWM_fun(void);
void Motor_fun(void);
void Network_fun(void);


typedef void (*menu_func)(void);

typedef struct {
	char *tekst;
	menu_func func;
}menu_t;

menu_t menu1[] = {
		{"RS232", Rs232_fun},
		{"PWM", PWM_fun},
		{"Motor",Motor_fun},
		{"Network",Network_fun},
};
void draw_menu (menu_t *menu, int menu_size,int sel);


uint8_t keylock[4];
int sel=0;


int main(){

	PORTD |= (1<<PREV)|(1<<OK)|(1<<UP)|(1<<DOWN);
	lcd_init();

	while(1){

	draw_menu(menu1,4,sel);

	if(!keylock[0] && !(PIND & (1<<DOWN))){
		keylock[0]=220;
		sel++;
		if(sel>3)sel=0;
	}else if (keylock[0] && (PIND & (1<<DOWN)))keylock[0]++;

	if(!keylock[1] && !(PIND & (1<<UP))){
		keylock[1]=220;
		sel--;
		if(sel<0)sel=3;
	}else if (keylock[1] && (PIND & (1<<UP)))keylock[1]++;
   }
}

void draw_menu (menu_t *menu, int menu_size,int sel){
	int i;
	for (i=0;i<menu_size;i++){
		if (i == sel){
			lcd_locate(i,0);
			lcd_char('>');
		}
		else{
			lcd_locate(i,0);
			lcd_char(' ');
		}
		lcd_locate(i,1);
		lcd_str(menu1[i].tekst);
	}
}

void Rs232_fun(void){

}
void PWM_fun(void){

}
void Motor_fun(void){

}
void Network_fun(void){

}

Największe wątpliwości mam co do tej funkcji, w której wyświetlam menu i wyświetlam ">" lub spacje. 

for (i=0;i<menu_size;i++){
		if (i == sel){
			lcd_locate(i,0);
			lcd_char('>');
		}
		else{
			lcd_locate(i,0);
			lcd_char(' ');
		}
		lcd_locate(i,1);
		lcd_str(menu1[i].tekst);
	}

Kolejnym krokiem, którym bym się chciał zająć jest funkcja menu_enter/ok, za pomocą której bym przechodził powiedzmy do sub_menu lub wywoływał daną funkcje. Tylko zastanawiam się jak tu powiązać zmienną sel z odpowiednimi elementami menu. 

Link do komentarza
Share on other sites

(edytowany)

Hejka, męczę się z pewnym problemem i potrzebowałbym porady bo myślę, że czegoś tu mocno nie rozumiem. Rozwijam kod prostego menu, który @Elvis napisał jakiś czas temu. Wszystko ładnie działa, rysowanie nowego menu, wywoływanie funkcji itp. Jednak chcę teraz dodać jakieś ustawienia, wyświetlać obok nazwy jakąś powiedzmy wartość i według potrzeb ją zmieniać. Zacząłem tak:

typedef struct {
	char *tekst;
	int properties;
	menu_func func;
}menu_t;

Dodałem nowy element do struktury "properties", które chcę wyświetlać jeśli zajdzie taka potrzeba. 

 menu_t menu1[] = {
		{"RS232",9600,Rs232_fun},
		{"PWM",0 ,PWM_fun},
		{"Motor",0,motor_setting},
		{"Network",0,Network_fun},
};

Gdy na sztywno wpiszę wartość properties, wszystko jest OK, wyświetla się dobrze. Jednak ja chciałbym mieć możliwość zmiany wartości, zwiększyć lub zmniejszyć, więc musiałaby tam być jakaś zmienna i tu zaczynają się schody.

int frame=9600;

 menu_t menu1[] = {
		{"RS232",frame,Rs232_fun},
		{"PWM",0 ,PWM_fun},
		{"Motor",0,motor_setting},
		{"Network",0,Network_fun},
};

Dostaje error : main.c:33:12: error: initializer element is not constant

więc dodaje operator &

{"RS232",&frame,Rs232_fun},

i dostaje warning :  warning: initialization makes integer from pointer without a cast [-Wint-conversion]

więc robię jawne rzutowanie 

{"RS232",(int)&frame,Rs232_fun},

Wtedy kompilacja przechodzi bez błędów, ale na LCD dostaje wartość 298, zamiast 9600. Gdy zmienna frame będzie miała wartość 0, to wyświetla mi wartość 348. 😕 Kompletnie nie wiem, o co tu chodzi. 

Pełny kod:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <stdio.h>
#include "lcd.h"


#define PREV PD0
#define OK PD6
#define UP PD5
#define DOWN PD7
int frame;
int baud;
void Rs232_fun(void);
void PWM_fun(void);
void Motor_fun(void);
void Network_fun(void);
void motor_setting(void);
void main_menu(void);

typedef void (*menu_func)(void);

typedef struct {
	char *tekst;
	int properties;
	menu_func func;
}menu_t;

 menu_t menu1[] = {
		{"RS232",(int)&frame,Rs232_fun},
		{"PWM",0 ,PWM_fun},
		{"Motor",0,motor_setting},
		{"Network",0,Network_fun},
};
 menu_t menu2[] = {
		{"FRAME",0 ,Motor_fun},
		{"BAUD",0,Network_fun},
		{"BACK",0, main_menu},
};

void draw_menu (menu_t *menu, int menu_size,int sel);
void use_menu( menu_t *menu, int menu_size);
uint8_t keylock[4];
int sel=0;


int main(){

	DDRD |= (1<<PD1);
	PORTD |= (1<<PREV)|(1<<OK)|(1<<UP)|(1<<DOWN);
	lcd_init();

	while(1){

	use_menu(menu1,4);
   }
}
void draw_menu (menu_t *menu, int menu_size,int sel){
	int i;
	for (i=0;i<menu_size;i++){
		if (i == sel){
			lcd_locate(i,0);
			lcd_char('>');
		}
		else{
			lcd_locate(i,0);
			lcd_char(' ');
		}
		lcd_locate(i,1);
		lcd_str(menu[i].tekst);
		if(menu[i].properties>0){
			lcd_locate(i,10);
			lcd_int(menu[i].properties);
		}

	}
}
void use_menu( menu_t *menu, int menu_size){

		while(1){
		draw_menu(menu,menu_size,sel);
		if(!keylock[0] && !(PIND & (1<<DOWN))){
			keylock[0]=220;
			sel++;
			if(sel>menu_size-1)sel=0;
		}else if (keylock[0] && (PIND & (1<<DOWN)))keylock[0]++;

		if(!keylock[1] && !(PIND & (1<<UP))){
			keylock[1]=220;
			sel--;
			if(sel<0)sel=menu_size-1;
		}else if (keylock[1] && (PIND & (1<<UP)))keylock[1]++;


		if(!keylock[2] && !(PIND & (1<<OK))){
			keylock[2]=220;
			menu[sel].func();
		}else if (keylock[2] && (PIND & (1<<OK)))keylock[2]++;

		if(!keylock[3] && !(PIND & (1<<PREV))){
			keylock[3]=220;

		}else if (keylock[3] && (PIND & (1<<PREV)))keylock[3]++;
	}
}

void main_menu(void){
	lcd_cls();
	use_menu(menu1,4);
}
void motor_setting(void){
lcd_cls();
	use_menu(menu2,3);
}
void Rs232_fun(void){
	PORTD |= (1<<PD1);
}
void PWM_fun(void){
	PORTD &=~ (1<<PD1);
}
void Motor_fun(void){
}
void Network_fun(void){
}

 

Edytowano przez Krawi92
Link do komentarza
Share on other sites

lepiej dla properites podstawić wskaźnik do edytowanej zmiennej 

typedef struct {
	char *tekst;
	int  * properties;
	menu_func func;
}menu_t;

lub jeszcze lepiej zrobić z niej void * ptr; ale jak już mamy taki zapis to wypełnienie powinno wyglądać:

int frame=9600,pwm = 120,motor = 44,network = 8888;

 menu_t menu1[] = {
		{"RS232",&frame,Rs232_fun},
		{"PWM",&pwm ,PWM_fun},
		{"Motor",&motor,motor_setting},
		{"Network",&network,Network_fun},
};

wyświetlenie i zmiana wartości:

lcd_int(*menu[0].properites);
 *menu[0].properites = 115200;
lcd_int(*menu[0].properites);

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Kolega @_LM_ rozwiązał problem z którym @Krawi92 się zetknął ale nie wytłumaczył skąd się wziął błąd.


int frame;

typedef void (*menu_func)(void);

typedef struct {
	char *tekst;
	int properties;
	menu_func func;
}menu_t;

 menu_t menu1[] = {
		{"RS232",(int)&frame,Rs232_fun},
		{"PWM",0 ,PWM_fun},
		{"Motor",0,motor_setting},
		{"Network",0,Network_fun},
};
 

Zadeklarowałeś zmienną frame typu int. W definicji struktury masz pole properties typu int. W tablicy menu1[] do pola int properties  przypisujesz (int)&frame czyli adres zmiennej frame rzutowany na typ int. W efekcie wyświetlać będziesz adres zmiennej frame, a nie jej wartość. Kolega @_LM_ rozwiązał problem ponieważ zmienił definicję struktury:

typedef struct {
	char *tekst;
	int  * properties;
	menu_func func;
}menu_t;

Zmienił pole int properties na wskaźnik do zmiennej typu int, a następnie przypisał do tego pola adres zmiennej frame.

int frame=9600,pwm = 120,motor = 44,network = 8888;

 menu_t menu1[] = {
		{"RS232",&frame,Rs232_fun},
		{"PWM",&pwm ,PWM_fun},
		{"Motor",&motor,motor_setting},
		{"Network",&network,Network_fun},
};

W ten sposób prawidłowo udało się wyświetlić lub zmodyfikować wartość pola z użyciem operatora wyłuskania *

*menu[0].properites = 115200;
lcd_int(*menu[0].properites);

Post uzupełniony w celach dydaktycznych dla potomnych 🙂

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.