Наши сомнения – это наши предатели. Они заставляют нас терять то, что мы, возможно, могли бы выиграть, если бы не боялись попробовать.
Уильям Шекспир

Меню навигации для мобильных

TM1638

Автор zenon, 07 Июль, 2023, 13:40

« предыдущая - следующая »

zenon

Сделал софтовый SPI на пробу для модуля на TM1638 с кнопками.
Макетом послужила лишняя плата приёмника.


main
↓ спойлер ↓
#include <stm32f0xx.h>
#include "tm1638_softspi.h"
// PIN_STB // PB4 STB SPI1_MISO // SPI3_CS_SET  SPI3_CS_CLR
// PIN_CLK // PB3 CLK SPI1_SCK  // SPI3_CLK_SET SPI3_CLK_CLR
// PIN_DIO // PB5 DIO SPI1_MOSI // SPI3_DIO_SET SPI3_DIO_CLR
volatile uint32_t ttms = 0;
volatile uint32_t pa2  = 0;
#define pin_toggle(gpioport, gpios)  do{  \
        register uint32_t __port = gpioport->ODR;  \
        gpioport->BSRR = ((__port & (gpios)) << 16) | (~__port & (gpios));}while(0)

void gpio_init(void)
{
  RCC->AHBENR  |= RCC_AHBENR_GPIOAEN  | RCC_AHBENR_GPIOBEN;

  GPIOA->MODER    &= ~ GPIO_MODER_MODER2;
  GPIOA->MODER    |=   GPIO_MODER_MODER2_0;
  GPIOA->OTYPER   &= ~ GPIO_OTYPER_OT_2;
  GPIOA->OSPEEDR  |=   GPIO_OSPEEDER_OSPEEDR2_0;
  
  GPIOB->MODER    &= ~( GPIO_MODER_MODER3       | GPIO_MODER_MODER4       | GPIO_MODER_MODER5 );
  GPIOB->MODER    |=  ( GPIO_MODER_MODER3_0     | GPIO_MODER_MODER4_0     | GPIO_MODER_MODER5_0 ) ;
  GPIOB->OTYPER   &= ~( GPIO_OTYPER_OT_3        | GPIO_OTYPER_OT_4        | GPIO_OTYPER_OT_5 ) ;
  GPIOB->OSPEEDR  |=  ( GPIO_OSPEEDER_OSPEEDR3_0|GPIO_OSPEEDER_OSPEEDR4_0 | GPIO_OSPEEDER_OSPEEDR5_0 );
}
void rcc_sysclockinit(void)
{
  RCC->CR = RCC_CR_HSEON;
  while(! (RCC->CR & RCC_CR_HSERDY));
  RCC->CFGR2 = RCC_CFGR2_PREDIV_DIV2;
  RCC->CFGR  = RCC_CFGR_PLLMUL4 | 
               RCC_CFGR_PLLSRC_HSE_PREDIV;
  RCC->CR |= RCC_CR_PLLON;
  FLASH->ACR = _VAL2FLD(FLASH_ACR_LATENCY, 1) | FLASH_ACR_PRFTBE;
  while(! (RCC->CR & RCC_CR_PLLRDY));
  RCC->CFGR |= RCC_CFGR_SW_PLL;
}

void blink_(uint16_t freq)
{
  if (pa2 > ttms || ttms - pa2 > freq)
  {
    pin_toggle(GPIOA, 1<<2);
    pa2 = ttms;
  }
}

int main(void) {
  uint16_t key;
  rcc_sysclockinit();
  SysTick_Config(48000);
  gpio_init();
  tm1638_init();
  do {
    blink_(499);
    key = tm1638_read_key();
    if (key < 8) {
      while (tm1638_read_key() == key)
        ;
      if (key == 0) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 1) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 2) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 3) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 4) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 5) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 6) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      } else if (key == 7) {
        // tm1638_write_data(7<<1,code_tab[key]);
        tm1638_tube_dip(key, key);
      }
    }
  } while (1);
}

void SysTick_Handler(void) 
{
  ++ttms;
}
[свернуть]


tm1638_softspi
↓ спойлер ↓
#include "tm1638_softspi.h"

#define DATA_COMMAND    0X40
#define DISP_COMMAND    0x80
#define ADDR_COMMAND    0XC0

#define SPI3_DIO_SET GPIOB->BSRR |= GPIO_BSRR_BS_5
#define SPI3_DIO_CLR GPIOB->BSRR |= GPIO_BSRR_BR_5
#define SPI3_CLK_SET GPIOB->BSRR |= GPIO_BSRR_BS_3
#define SPI3_CLK_CLR GPIOB->BSRR |= GPIO_BSRR_BR_3
#define SPI3_CS_SET  GPIOB->BSRR |= GPIO_BSRR_BS_4
#define SPI3_CS_CLR  GPIOB->BSRR |= GPIO_BSRR_BR_4
#define SPI3_CHECK_DIO pin_read(GPIOB, 1<<5)


unsigned char code_tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};

void tm1638_write_byte(unsigned char data) {
  unsigned char i;
  for (i = 0; i < 8; i++) {
    SPI3_CLK_CLR; 
    if (data & 0x01)
      SPI3_DIO_SET;
    else
      SPI3_DIO_CLR; 
    data >>= 1;
    SPI3_CLK_SET; 
  }
}

unsigned char tm1638_read_byte(void) {
  unsigned char i;
  unsigned char temp = 0;
  SPI3_DIO_SET;
  for (i = 0; i < 8; i++) {
    temp >>= 1;
    SPI3_CLK_CLR;
    if (SPI3_CHECK_DIO)
      temp |= 0x80;
    SPI3_CLK_SET;
  }
  return temp;
}

void tm1638_write_com(unsigned char cmd) {
  SPI3_CS_CLR;
  tm1638_write_byte(cmd);
  SPI3_CS_SET;
}

unsigned char tm1638_read_key(void) {
  unsigned char c[4], i, key_value = 0;
  SPI3_CS_CLR;
  tm1638_write_byte(0x42);
  for (i = 0; i < 4; i++)
    c[i] = tm1638_read_byte();
  SPI3_CS_SET;
  for (i = 0; i < 4; i++)
    key_value |= c[i] << i;
  for (i = 0; i < 8; i++)
    if ((0x01 << i) == key_value)
      break;
  return i;
}

void tm1638_write_data(unsigned char add, unsigned char data) {
  tm1638_write_com(0x44);
  SPI3_CS_CLR;
  tm1638_write_byte(0xc0 | add);
  tm1638_write_byte(data);
  SPI3_CS_SET;
}

void tm1638_write_led(unsigned char led_flag) {
  unsigned char i;
  for (i = 0; i < 8; i++) {
    if (led_flag & (1 << i))
      tm1638_write_data(2 * i + 1, 1);
    else
      tm1638_write_data(2 * i + 1, 0);
  }
}

void tm1638_init(void) {
  unsigned char i;
  tm1638_write_com(0x8b);
  tm1638_write_com(0x40);
  SPI3_CS_CLR;
  tm1638_write_byte(0xc0);
  for (i = 0; i < 16; i++)
    tm1638_write_byte(0x00);
  SPI3_CS_SET;
}
extern unsigned char num[8];
void tm1638_tube_dip(uint16_t pos, uint16_t data) {
  tm1638_write_data(pos * 2, code_tab[data]);
  tm1638_write_led(1 << data);
}
[свернуть]


↓ спойлер ↓
[свернуть]
Третий и четвертый светодиоды не работают... :)
ы. Как ни странно задержки в код не добавлял совсем...
https://github.com/minamonra/

zenon

А вот железный SPI заставил опять подключить анализатор, сделал отправку.
Примерчик размещу на гитхабе, заминка в основном была из-за того, что микросхема принимает байты младшим битом вперёд (LSBFIRST).
Вот такой инит и передача байта вышли:
#define CS_SET GPIOB->BSRR |= GPIO_BSRR_BS_4
#define CS_CLR GPIOB->BSRR |= GPIO_BSRR_BR_4

static void spi_init(void)
{
  RCC->AHBENR   |= RCC_AHBENR_GPIOBEN;
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
  // SCK  PB3
  GPIOB->MODER |= GPIO_MODER_MODER3_1;  // alternate function
  // MOSI  PB5
  GPIOB->MODER |= GPIO_MODER_MODER5_1;  // alternate function
  // soft nCS   PB4
  GPIOB->MODER |= GPIO_MODER_MODER4_0; // PB4 as output
  GPIOB->OSPEEDR  |=  ( GPIO_OSPEEDER_OSPEEDR4_0);
  CS_SET; //GPIOB->ODR = GPIO_ODR_4; // deselect
  SPI1->CR1 |= SPI_CR1_BR_1; // set prescaler FCY=16MHz / prescaler(8) = 2 MHz (0b010)
  SPI1->CR1 |= SPI_CR1_LSBFIRST; // !!
  SPI1->CR1 |= SPI_CR1_MSTR; // бит мастера (SPI_CR1_MSTR)
  SPI1->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; // software slave CS management & internal slave select
  SPI1->CR2 |= SPI_CR2_FRXTH; // бит наличия данных в очереди на четверть длины - 8 бит (SPI_CR2_FRXTH)
  SPI1->CR2 |= SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0; //8-bit
  SPI1->CR1 |= SPI_CR1_SPE; // SPI вкл
}
отправка:
uint8_t spi_send_byte(uint8_t data)
{
  while (!(SPI1->SR & SPI_SR_TXE)); // TX buffer is empty
  *(volatile uint8_t *) & SPI1->DR = data;
  while (!(SPI1->SR & SPI_SR_RXNE)); // while (!(SPI1->SR & SPI_SR_BSY)); //
  return *(volatile uint8_t *) & SPI1->DR;
}
https://github.com/minamonra/

zenon

#2
Уффф. Чтение осилил.
Оказывается бит SPI_CR1_BIDIMODE надо включить, потом четыре байта прочесть.
uint8_t tm1638_get_key(void)
{
  uint8_t i, key_value = 0;
  CS_CLR;
  spi_send_byte(0x42);
  SPI1->CR1 |= SPI_CR1_BIDIMODE;  // вкл bi-directional mode
  for (i = 0; i < 4; i++)
    key_value |= spi_send_byte(0xFF) << i;
  CS_SET;
  SPI1->CR1 &= ~SPI_CR1_BIDIMODE; // выкл bi-directional mode
  return key_value;
}


:: добавлено 30 Июль, 2023, 20:27
Ну вот как-то так https://github.com/minamonra/my_stm_snippets/tree/main/F0/tm1638/tm1638hw
В мэйне код - 4-ре первых сегмента счёт, на других вывод кода нажатой кнопки.
https://github.com/minamonra/