Запустил таки wh1602b на stm8

Страшный код по катом.
/* 
00000000 биты
76543210 пины
 */
#include <stm8/stm8s105c_s.h>
#include <intrins.h> // nop is defined here

#define pin_0 0b00000001
#define pin_1 0b00000010
#define pin_2 0b00000100
#define pin_3 0b00001000 
#define pin_4 0b00010000
#define pin_5 0b00100000
#define pin_6 0b01000000
#define pin_7 0b10000000

#define pin_rs					pin_6
#define pin_rw					pin_5
#define pin_e						pin_4

#define pin_d7					pin_3 // подключения по 4-х битной шине всегда так как показанно.
#define pin_d6					pin_2
#define pin_d5					pin_1
#define pin_d4					pin_0
#define shift						pin_0

#define port_direction  PB_DDR
#define port_settings_1 PB_CR1
#define input_port			PB_IDR
#define output_port			PB_ODR

#define rs_1	output_port |=  pin_rs
#define rs_0	output_port &=~ pin_rs
#define e_1 	output_port |=  pin_e
#define e_0		output_port &=~ pin_e
#define rw_1	output_port |=  pin_rw
#define rw_0	output_port &=~ pin_rw
					
#define Function_set 							0b00101000//4-bit,2 - line mode, 5*8 dots
#define Display_on_off_control		0b00001100// display on,cursor off,blink off
#define Display_clear							0b00000001
#define Entry_mode_set						0b00000110//increment mode,entrir shift off
					
void init_port_out(void);
void delay( unsigned short ms);
void Lcd_write_cmd(unsigned char cmd);
void Lcd_write_data(unsigned char dat);
void Lcd_init(void);
void Lcd_write_str(unsigned char *STRING);
void Lcd_goto(unsigned char x,unsigned char y);

const unsigned char russian[]={ 0x41, 0xA0, 0x42, 0xA1, 0xE0, 0x45,
0xA3, 0xA4, 0xA5,0xA6, 0x4B, 0xA7, 0x4D, 0x48, 0x4F, 0xA8, 0x50,0x43,
0x54, 0xA9, 0xAA, 0x58, 0xE1, 0xAB, 0xAC, 0xE2, 0xAD,0xAE, 0x62,
0xAF, 0xB0, 0xB1, 0x61, 0xB2, 0xB3, 0xB4, 0xE3, 0x65, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0x6F, 0xBE, 0x70, 0x63,0xBF,
0x79, 0xE4, 0x78, 0xE5, 0xC0, 0xC1, 0xE6, 0xC2,0xC3, 0xC4, 0xC5,
0xC6, 0xC7 };

void init_rc()
{// Настройка тактового генератора
	CLK_ECKR = 0b00000001;// Вкючаем HSE
	CLK_SWCR = 0b00000010;// Разрешаем переключение источника тактовой частоты
	while(CLK_ECKR == (1<<1)) {}//Ждем готовности источника тактирования
	CLK_CKDIVR = 0b00000000;// Предделитель равен нулю
	CLK_SWR = 0xB4;// Выбираем HSE источником тактовой частоты
  while(CLK_SWCR == (1<<3)){}
}

void main()
{   
		init_rc();
		Lcd_init();
		Delay(100);
    Lcd_write_str("Привет");
		for (;;)
    {  	
    }
}

void Lcd_init()
{
	
	delay(62000);
	Lcd_write_cmd(Function_set);
	delay(62000);

	Lcd_write_cmd(Display_on_off_control);
	delay(62000);

	Lcd_write_cmd(Display_clear);
	delay(62000);

	Lcd_write_cmd(Entry_mode_set);
}



void Lcd_write_str(unsigned char *STRING)
{
	char c; //символ из строки
	while (c=*STRING++){
	if(c>=192) Lcd_write_data(russian[c-192]);
	else Lcd_write_data(c);
	}
}


void Lcd_goto(unsigned char x,unsigned char y)
{
	int str;
	str = y + 0x80;
	if(x == 1)
	{
	str+= 0x40;
	}
	Lcd_write_cmd(str);
}

void init_port_out(void)
{
	port_direction  |= pin_rs | pin_rw | pin_e | pin_d7 | pin_d6 | pin_d5 | pin_d4; 
	port_settings_1 |= pin_rs | pin_rw | pin_e | pin_d7 | pin_d6 | pin_d5 | pin_d4;
}


void delay( unsigned short ms)
{
  unsigned short d = 0;
	for (d = 0; d < ms; d++)
        {
            _nop_();
        }
}

void Lcd_write_cmd(unsigned char cmd )
{
	Init_port_out();
	delay(100);
	rs_0;
	rw_0;
	output_port = (0xF0 &cmd)>>4;
	rs_0;
	rw_0;
	delay(10);
	e_1;
	delay(10);
	e_0;
	output_port =(0x0F & cmd);
	rs_0;
	rw_0;
	delay(10);
	e_1;
	delay(10);
	e_0;
	rs_0;
	rw_0;
}

void Lcd_write_data(unsigned char dat)
{
	Init_port_out();
	delay(100);
	rs_1;
	rw_0;
	output_port = (0xF0 &dat)>>4;;
	rs_1;
	rw_0;
	e_1;
	delay(100);
	e_0;
	output_port = (0x0F & dat);
	rs_1;
	rw_0;
	delay(100);
	e_1;
	delay(100);
	e_0;
	rs_0;
	rw_0;
}

Комментарии (30)

RSS свернуть / развернуть
… я не знаком с особенностями контроллеров stm8, но зачем при каждой записи (данных или команд) вызывать функцию Init_port_out(); (в описании она init_port_out)? Пусть уж лучше при чтении менять направление портов.

ЗЫ… может быть надо было?
void init_port_out(void)
{
        port_direction  |= (1<<pin_rs) | (1<<pin_rw) | (1<<pin_e) | (1<<pin_d7) | (1<<pin_d6) | (1<<pin_d5) | (1<<pin_d4); 
        port_settings_1 |= (1<<pin_rs) | (1<<pin_rw) | (1<<pin_e) | (1<<pin_d7) | (1<<pin_d6) | (1<<pin_d5) | (1<<pin_d4);
}
0
почему?
0
с инициализацией портов каждый раз да, вы правы. Лишняя работа для мк.
0
… да и задержки (или как минимум большие) не особо нужны — если только при инициализации и очистки дисплея
0
… да и функцию Lcd_write_cmd, имхо, лучше переписать
void Lcd_write_cmd(unsigned char cmd )
{
        //Init_port_out(); инициализировать только один раз в начале программы
        rs_0;
        rw_0;
        output_port |= (0xF0 &cmd)>>4;
        e_1;
        delay(10); // может надо меньше?
        e_0;
        output_port |=(0x0F & cmd);
        e_1;
        delay(10);
        e_0;
}
0
… также и с Lcd_write_data()
0
… упс, только
output_port |= (0xF0 &cmd)>>4;

не пойдет. Надоб добавить еще затирание перед записью
void Lcd_write_cmd(unsigned char cmd )
{
 //Init_port_out(); инициализировать только один раз в начале программы        
 rs_0;        
 rw_0;
 output_port &=~0x0F;       
 output_port |= (0xF0 &cmd)>>4;        
 e_1;        
 delay(10); // может надо меньше?        
 e_0;        
 output_port &=~0x0F;
 output_port |=(0x0F & cmd);        
 e_1;        
 delay(10);        
 e_0;
}
… а то получится каша
0
… также и с const unsigned char russian[]. Если дисплей поддерживает кириллицу то можно и без этого массива, если нет то символы надо рисовать
0
Массив нужен для преобразования кодов. Кириллицу он может и поддерживать, только коды символов не совпадают…
0
… это я тормазнул
0
Не нужен массив. Достаточно в редакторе установить нужную кодировку. Обычно дисплеи используют кодировку CP866, а иногда — CP1251. В общем достаточно просто писать исходник разу в нужной кодировке. Не все IDE/редакторы позволяют выбирать кодировку. Однако, кириллические строки в исходнике можно по редактировать и во внешнем редакторе, который поддерживает нужную кодировку. Обычно это лучше, чем иметь большой массив и каждую строку на лету перекодировать.
-1
У WH1602 нет походу никакого соответствия ни одной из кодировок кирилических. Буквы кирилицы там напиханы по остаточному принципу куда придется.
0
Это печально (с)
Мне попадались только дисплеи, в которых вполне нормальная CP866 кодировка была.
0
Там совсем своя кодировка, причем для кириллицы есть только те символы, которых нету в латинице. Отсюда и программы перекодировки, чтобы вставлять в код строки уже в кодировке дисплея.
0
Я смотрю, там вообще разброд и шатания. У разных производителей могут быть разные кодировки для кириллицы, я нашел две часто встречающиеся. Одна используется в оригинальном HD44780, другая — в KS0066. Плюс еще куча «кастомных» кодировок, среди которых попадаются и стандартные, типа CP866.
Я всё равно считаю, что строки перекодировать лучше не во время выполнения, а во время компиляции. Делать это, например, специальной утилитой запускаемой перед сборкой из мейкфайла.
0
Спасибо за комментарии.
0
output_port= (0xF0 &cmd)>>4; 
— побитовой ИЛИ не ставил чтобы затирать содержимой предидущей тетрады.
0
А зачем вообще обнулять биты, которые ты все равно сбрасываешь сдвигом? Я еще понимаю (cmd >> 4) & 0x0F.
0
если ставить или сдвигом не затарались. Смотрел при отладке. Может я не туда посмотрел?
ST Visual Develop + Raisonance
0
Так быть не должно вроде (хотя я не знаю С и не уверен, обязан ли он обнулять биты, освобождающиеся при сдвиге). Ну и обнулять биты, которые ты сбрасываешь сдвигом в любом случае странно. Надежней обнулить старшую тетраду после сдвига, если не уверен.
0
Вот тогда думаю лучше сделаю обнуление вручную.
0
Правильней писать не
UART2_CR2 |= (MASK_UART2_CR2_REN)|(MASK_UART2_CR2_TEN); // Разрешить TX, RX.
а
UART2_CR2 = (MASK_UART2_CR2_REN)|(MASK_UART2_CR2_TEN); // Разрешить TX, RX.
Сравните код и вы поймёте.

0
* 2 eugenemcu (21.12.2010 09:58) [Материал]
К сожалению, не понял Вашу мысль. Зачем мне сбрасывать остальные биты в этом регистре? Может быть, я посреди программы решил воспользоваться этими выводами как GPIO, а потом снова решил вернуться к работе с UART. И при этом не хочу сбрасывать, скажем, разрешения прерываний, которые установил до этого.
В инициализационной части программы сделал бы точно так, как вы написали. А это общий пример работы с битами, не должен зависеть от контекста программы.

eugenemcu.ru/publ/11-1-0-69
0
с битами надо быть осторожнее, может по этому мои таймеры на авр не хотели запускаться, я же не помню. :-)
0
Причем тут это вообще? Я говорю, что в куске кода (0xF0 &cmd)>>4 нет смысла, он полностью идентичен коду cmd >> 4.
0
а это для меня, чтобы понятнее было.
0
чтобы понятнее было
А чтобы понятнее было… все эти финты с битами для того, чтобы не затирались биты неиспользуемой тетрады, т. е. которые не используются для вывода данных на LCD… т. к они могут быть использованы в других целях… И делается это, как правило, через дополнительную переменную… чтобы возня с портом биты не попутала… т.к. вся эта вакханалия не атомарная…
0
… к тому же не атомарная…
0
если оставить «или», сдвигом не затирались, смотрел при отладке. Может я не туда посмотрел?
ST Visual Develop + Raisonance
0
code.google.com/p/pinboard-ii-arm/source/browse/src/WH1602B.h?r=9948b3678131a8e1ccdad7b1a527ddf7ffdae3ef
Гы, я и не думал что мой страшный код кому-то окажется нуженю
0
тфьу ты, не в ту тему пульнул. По ссылке на стм32 код. Глюченный по 4 битной шине.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.