STM32F и LCD 1602a или hd44780 описание работы, примеры программ для обмена информацией.
Ссылка на видео в YouTube В предыдущей статье я попробовал описать как происходит настройка, обмен информацией между LCD 1602a и контроллером STM8S так что второй раз описывать эти процессы для STM32F( STM32F105RB) смысла нет, если кому интересно проходим по ссылке и ознакомляемся, здесь я выложу основную информацию для удобства и конечно примеры программ с описанием.
Начнем конечно со схемы подключения, из за рациональности для передачи данных будем использовать только 4 битную линию связи.
Из особенности подключения, не забываем что LCD питается от пяти вольтов а контроллер три вольта поэтому пины должны быть с пометкой FT( выдерживают 5 вольт) и могут быть только GPIO_Mode_Out_OD( на вывод данных) или GPIO_Mode_IN_FLOATING( как входы). Да не забываем подтянуть вывод E в LCD к питанию через резистор 1.5к, остальные RS, R/W и D4-D7 рекомендую тоже но резистор может быть около 5к.
Документация.
Для удобства выложу необходимые документы которые помогут при написание своей программы для настройки или обмена данными с модулем LCD.
Таблица команд.
Адреса видеопамяти для вывода символов.
Коды символов.
Примеры программ.
Внимание! В функциях отправки команд, данных у меня стоят задержки Pause( 5) и Pause( 10000) значение в которых вы должны изменить в зависимости от тактирования, если частота больше то и задержка должна быть больше, что бы LCD успевал отработать команды и данные.
В первом примере мы просто создаем массив с символами PROGCONT.ru и в цикле выводим, с начало с начальной позиции потом с конца второй строки в обратном порядке.
#include "stm32f10x.h"
//Функция отсылает команды как бы по восьмибитной линии данных.
void Send_Comand_8bit( uint16_t comand);
//Функция отсылает команды по четырехбитной линии данных.
void Send_Comand_4bit( uint16_t data);
//Функция отсылает данные по четырехбитной линии данных.
void Send_Data_4bit( uint16_t data);
void Pause( uint32_t count){ for( uint32_t i=count; i>0; i--);};
//Массив PROGCONT.ru.
uint8_t text[11]={ 80, 82, 79, 71, 67, 79, 78, 84, 46, 114, 117};
int main()
{
RCC_DeInit();
//Включаем тактирование GPIOB, настраиваем выводы для RS, R/W, E и D4-D7.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef Pin_out;
Pin_out.GPIO_Pin= GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
Pin_out.GPIO_Speed= GPIO_Speed_10MHz;
Pin_out.GPIO_Mode= GPIO_Mode_Out_OD;
GPIO_Init( GPIOB, &Pin_out);
//Инициализация и настройка LCD.
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 32);
Send_Comand_4bit( 40);
Send_Comand_4bit( 14);
Send_Comand_4bit( 1);
while(1){
//Очищаем экран и возвращаем курсор в начальную позицию.
Send_Comand_4bit( 1);
//Выводим PROGCONT.ru с начальной позиции.
for( uint8_t i=0; i<11; i++){
Send_Data_4bit( text[i]);
Pause( 100000);
}
// Меняем направление курсора и устанавливаем его в конец второй строки.
Send_Comand_4bit( 4);
Send_Comand_4bit( 207);
//Выводим PROGCONT.ru в обратном порядке.
for( uint8_t i=10; i!=255; i--){
Send_Data_4bit( text[i]);
Pause( 100000);
}
Pause( 1000000);
}
return 0;
}
void Send_Comand_8bit( uint16_t comand){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=( comand<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
void Send_Comand_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
void Send_Data_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_10);//Сброс R/W.
GPIO_SetBits( GPIOB, GPIO_Pin_11);//Устанавливаем высокий RS.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
Второй пример будем выводить русские буквы и значение счетчика.
#include "stm32f10x.h"
void Send_Comand_8bit( uint16_t comand);
void Send_Comand_4bit( uint16_t data);
void Send_Data_4bit( uint16_t data);
void Pause( uint32_t count){ for( uint32_t i=count; i>0; i--);};
//Функция отображения чисел.
void Displ_Number( uint32_t number);
//Массивы букв.
uint8_t ey[8]={ 0x0A, 0x00, 0x1F, 0x10, 0x1E, 0x10, 0x1F,0x00};//Буква Ё
uint8_t ch[8]={ 0x11, 0x11, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x00};//Буква Ч
uint8_t i[8]={ 0x11, 0x11, 0x13, 0x15, 0x19, 0x11, 0x11, 0x00};//Буква И
int main()
{
RCC_DeInit();
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef Pin_out;
Pin_out.GPIO_Pin= GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
Pin_out.GPIO_Speed= GPIO_Speed_10MHz;
Pin_out.GPIO_Mode= GPIO_Mode_Out_OD;
GPIO_Init( GPIOB, &Pin_out);
//Инициализация и настройка LCD.
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 32);
Send_Comand_4bit( 40);
//Отключаем отображение курсора.
Send_Comand_4bit( 12);
Send_Comand_4bit( 1);
//Загружаем символ Ё в позицию 0.
Send_Comand_4bit( 64);
for( uint8_t q=0; q<8; q++){ Send_Data_4bit( ey[q]);}
//Загружаем символ Ч в позицию 1.
Send_Comand_4bit( 72);
for( uint8_t q=0; q<8; q++){ Send_Data_4bit( ch[q]);}
//Загружаем символ И в позицию 2.
Send_Comand_4bit( 80);
for( uint8_t q=0; q<8; q++){ Send_Data_4bit( i[q]);}
while(1){
Send_Comand_4bit( 1);
//Стандартно выводим наши символы.
Send_Data_4bit( 67);//C
Send_Data_4bit( 1);//Ч
Send_Data_4bit( 0);//Ё
Send_Data_4bit( 84);//T
Send_Data_4bit( 1);//Ч
Send_Data_4bit( 2);//И
Send_Data_4bit( 75);//K
Send_Data_4bit( 58);//:
//Цикл из которого будем выводить количество его повторений.
for( uint32_t count=0; count<50000000; count++){
//Устанавливаем курсор в нужную позицию для отображения числа счетчика.
Send_Comand_4bit( 136);
Displ_Number( count);
}
}
return 0;
}
void Send_Comand_8bit( uint16_t comand){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=( comand<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
void Send_Comand_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
void Send_Data_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_10);//Сброс R/W.
GPIO_SetBits( GPIOB, GPIO_Pin_11);//Устанавливаем высокий RS.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(10000);
}
void Displ_Number( uint32_t number){
Send_Data_4bit( number/10000000+48);
number= number-(number/10000000*10000000);
Send_Data_4bit( number/1000000+48);
number= number-(number/1000000*1000000);
Send_Data_4bit( number/100000+48);
number= number-(number/100000*100000);
Send_Data_4bit( number/10000+48);
number= number-(number/10000*10000);
Send_Data_4bit( number/1000+48);
number= number-(number/1000*1000);
Send_Data_4bit( number/100+48);
number= number-(number/100*100);
Send_Data_4bit( number/10+48);
number= number-(number/10*10);
Send_Data_4bit( number+48);
}
Остался последний пример в котором будем читать данные из LCD, в нем появилась новая функция которая возвращает байт состоящий из флага BF( старший бит) и адреса положения курсора AC( остальные 6-0 биты). Данную функцию можно применить для сканирования занятости LCD проверяя старший бит возвращаемого байта или узнать текущее положение курсора.
Внимание! Подтягивающий резистор у вывода LCD E( Enable) не должен превышать 1.5к для быстрого перехода с низкого на высокий уровень, если резистор будет превышать это сопротивление возможны сбои при чтение данных.
#include "stm32f10x.h"
void Send_Comand_8bit( uint16_t comand);
void Send_Comand_4bit( uint16_t data);
void Send_Data_4bit( uint16_t data);
//функция опрашивает LCD, возвращает 1 байт у которого седьмой бит состояние флага BF остальные биты AC( положение курсора).
uint8_t Read_Data_4bit( void);
void Pause( uint32_t count){ for( uint32_t i=count; i>0; i--);};
GPIO_InitTypeDef Pin_out;
int main()
{
RCC_DeInit();
//Включаем тактирование GPIOB, настраиваем выводы для RS E-9, R/W-10, RS-11 и D4-12, D5-13, D6-14, D7-15.
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
Pin_out.GPIO_Pin= GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
Pin_out.GPIO_Speed= GPIO_Speed_10MHz;
Pin_out.GPIO_Mode= GPIO_Mode_Out_OD;
GPIO_Init( GPIOB, &Pin_out);
//Инициализация и настройка LCD.
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 48);
Send_Comand_8bit( 32);
Send_Comand_4bit( 40);
Send_Comand_4bit( 14);
Send_Comand_4bit( 1);
while(1){
//Очищаем экран и возвращаем курсор в начальную позицию.
Send_Comand_4bit( 1);
//Выводим цифры 0-1-2-3-4 и потом адрес AC положения курсора.
Send_Data_4bit( 48);
Send_Data_4bit( 49);
Send_Data_4bit( 50);
Send_Data_4bit( 51);
Send_Data_4bit( 52);
Pause( 1000000);
Send_Data_4bit( Read_Data_4bit( )+48);
Pause( 1000000);
}
return 0;
}
uint8_t Read_Data_4bit( void){
uint16_t number_BF_pos=0;
//Перенастройка выводов контроллера для D4-D7 как входы.
Pin_out.GPIO_Pin= GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
Pin_out.GPIO_Mode= GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOB, &Pin_out);
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_11);//Устанавливаем низкий уровень RS.
GPIO_SetBits( GPIOB, GPIO_Pin_10);//Высокий уровень R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
Pause( 5);
//Читаем старшие 4 бита.
number_BF_pos=GPIO_ReadInputData( GPIOB)&61440;
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
Pause( 5);
//Читаем младшие 4 бита.
number_BF_pos|= GPIO_ReadInputData( GPIOB)>>4;
number_BF_pos>>=8;
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Сброс E.
GPIO_ResetBits( GPIOB, GPIO_Pin_10);//Сброс R/W.
//Перенастройка выводов контроллера для D4-D7 как выходы.
Pin_out.GPIO_Pin= GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
Pin_out.GPIO_Speed= GPIO_Speed_10MHz;
Pin_out.GPIO_Mode= GPIO_Mode_Out_OD;
GPIO_Init( GPIOB, &Pin_out);
return (uint8_t)(number_BF_pos);
}
void Send_Comand_8bit( uint16_t comand){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=( comand<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(2000);
}
void Send_Comand_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(2000);
}
void Send_Data_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_10);//Сброс R/W.
GPIO_SetBits( GPIOB, GPIO_Pin_11);//Устанавливаем высокий RS.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause(2000);
}
Использовать функцию чтения данных можно вместо пауз в конце каждой функций просто проверяя флаг BF, для этого пример на одной из функций.
void Send_Comand_4bit( uint16_t data){
GPIO_ResetBits( GPIOB, GPIO_Pin_11| GPIO_Pin_10);//Сброс RS и R/W.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<8)&61440;//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
Pause( 5);
GPIO_SetBits( GPIOB, GPIO_Pin_9);//Устанавливаем высокий E.
GPIOB->ODR&=4095;//Очищаем выводы для новых данных.
GPIOB->ODR|=(data<<12);//Устанавливаем данные.
Pause( 5);
GPIO_ResetBits( GPIOB, GPIO_Pin_9);//Устанавливаем низкий уровень E.
//Проверка флага BF, зацикливание пока он не сбросится.
while( Read_Data_4bit()&128);
}