STM8S выводим информацию и управляем контролером с помощью модуля на чипе TM1638 или как написать собственный драйвер.
Ссылка на видео в YouTube Как то в далекой галактике!
Короче решил я сконструировать частотный преобразователь для асинхронного трехфазного двигателя на контролере stm8s903k3 и само собой возник вопрос как им управлять. Делать самому индикацию и выводить кнопки управления как то не хотелось, так как пришлось бы нагрузить этой работой контролер, задействовать много ног у него, плюс дополнительные компоненты, пайка деталей.
И тут конечно случайно наткнулся на данный модуль на чипе TM1638, причем порадовала цена около 90 руб на любимом AliExpress.
Что хорошего у этой платы: 8 цифровых индикатора, 8 дополнительных светодиода, восемь кнопок управления и все это подключается к контролеру через три вывода(STB, CLK, DIO). Обмен информации происходит по SPI причем для передачи данных модулю и получение от него состояния кнопок происходит по двунаправленной линии DIO.
Ниже схема как у меня подключен модуль к контролеру, все по datasheet единственное вывод модуля STB можно подключить к любому свободному выводу контролера.
Модуль готов к работе сразу после его включения, особых действий для инициализации делать не нужно. Теперь как модуль принимает команды, данные и как они должны отправляться.
На картинке мы видим, что по выводу CLK происходит тактирование, по DIO принимает и отправляет данные тут все стандартно, а вот STB предназначен для стробирования команд то есть когда происходит спад напряжения модуль понимает что должна прийти команда, а за ней могут идти только данные. Для другой команды придется опять поднять напряжение на выводе STB и опять его опустить как на картинке выше, при высоком состоянии вывода модуль не воспринимает команды и данные только в низком состоянии.
Теперь о командах, у модуля имеется три вида команд: управление данными(записываем данные в модуль или сканируем кнопки), установка адреса для записи данных(устанавливаем адрес с которого будем менять данные или в который запишем новые) и управление самим модулем(включить, выключить и яркость индикации).
Описание команд, смотрите ниже.
Передача данных происходит после команды установившей адрес, четные адреса для символов и нечетные для управления светодиодом(8 бит для символа и 8 бит для светодиода).
Формировать символы мы будем по схеме с права, вывод SEG1 соответствует элементу а который будет являться младшим битом(bit0) данных, записав туда единицу мы его зажжем, элемент b это bit1 и так далее. Например что бы отобразить ноль, байт данных должен быть b00111111(0x3f).
Управлять светодиодом проще надо записать в байт соответствующего адреса, в бит 0 (bit0) единицу зажигаем, погасить ноль.
Ниже схема как будет выглядеть общение контролера с модулем.
Программа для контролера работает следующим образом, после старта загораются все светодиоды кроме символьных, нажимаем кнопку и напротив загорается символ U, светодиод гаснет.
Тут я отмечу три основные функции: send_command() которая отсылает команды, scan_button() возвращает 1байт результат нажатий(1бит первая кнопка, 2бит вторая и т.д), send_data() получает на вход 16байтный массив данных и байт сканирования кнопок, чтобы зажечь нужный символ и погасить светодиод.
Ниже рабочий код под 16МГц внешний кварц, в настройке SPI тактирование передачи данных равна f MASTER /16(1МГц), пробовал f MASTER /8(2МГц) тоже стабильно работало.
#include "stm8s.h"
#define display_on 143
#define auto_inc_adres 64
#define set_adres_0 192
#define scan_button_press 66
void send_command(uint8_t com);
void send_data(uint8_t *send_data_display, uint8_t scan);
uint8_t scan_button(void);
int main( void ){
//Включаем тактирование от внешнего источника, кварц 16МГц
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);
CLK_HSICmd(DISABLE);
CLK_LSICmd(DISABLE);
//Настраиваем порты для SPI
GPIO_Init(GPIOC,GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST);
GPIO_Init(GPIOC,GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST);
//Настраиваем SPI и включаем
SPI_Init( SPI_FIRSTBIT_LSB, SPI_BAUDRATEPRESCALER_16, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_1LINE_TX, SPI_NSS_SOFT, 0x07);
SPI_Cmd(ENABLE);
//Массив для отправки данных
uint8_t send_data_display[16];
//Включаем модуль и устанавливаем максимальную яркость
send_command(display_on);
//Задаем автоматический инкремент адреса для данных
send_command(auto_inc_adres);
while(1){
//Опрашиваем модуль на нажатие кнопок и отправляем данные для отображения
send_data(send_data_display, scan_button());
}
}
//Функция для отправки команды
void send_command(uint8_t com){
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(com);
while( (SPI->SR & SPI_FLAG_BSY) );
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
}
//Функция для опроса кнопок
uint8_t scan_button(void){
uint8_t scan_result;
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(scan_button_press);
while( (SPI->SR & SPI_FLAG_BSY) );
//Перенастраиваем SPI на прием данных, принимаем 4байта и сокращаем их до 1байта
SPI_BiDirectionalLineConfig(SPI_DIRECTION_RX);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result=SPI->DR;
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<1);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<2);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<3);
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
//Перенастраиваем SPI на передачу данных
SPI_BiDirectionalLineConfig(SPI_DIRECTION_TX);
return scan_result;
}
//Функция для отправки данных
void send_data(uint8_t *send_data_display, uint8_t scan){
uint8_t shift=1;
for(uint8_t i=0;i<16;i+=2){
if(shift & scan){send_data_display[i]=62;}
else{send_data_display[i]=0;}
shift<<=1;
}
shift=1;
for(uint8_t i=1;i<16;i+=2){
if(shift & scan){send_data_display[i]=0;}
else{send_data_display[i]=1;}
shift<<=1;
}
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(set_adres_0);
while( (SPI->SR & SPI_FLAG_BSY) );
for( uint8_t i=0;i<16;i++){
SPI_SendData(send_data_display[i]);
while( !(SPI->SR & SPI_FLAG_TXE) );
}
while( (SPI->SR & SPI_FLAG_BSY) );
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif
Я надеюсь что помог вам научится управлять TM1638 или в написании собственного драйвера.