PROGCONT.RU

Форма входа







Регистрпция Вход/

STM32F проект часов с индикацией на модуле TM1638.

Ссылка на видео в YouTube Прошу удержатся от высказываний, что использовать данный контролер для часов это расточительство и в нем есть готовый модуль для часов, а не использовать TIM1, суть статьи сопряжение и передача информации, а для чего использовать контролер и модуль будете решать сами.
 Тут я не буду описывать, как работает чип TM1638, потому что есть похожая статья для STM8S и там есть нужная информация, вот ссылка как работает TM1638, так же в интернете много информации по этой микросхеме.
 Первым делом нам нужно подключить 5V модуль к 3.3V контролеру(STM32F105RB), разработчик предусмотрел данную трудность и создал некоторые выводы толерантными к 5V, помеченные в описании контролера как FT.

 Это означает, что эти GPIO выдерживают 5V но должны быть настроены только как Input floating, Output open-drain или Alternate function open-drain другие варианты могут вывести контролер из строя так как 5V попадет в его 3.3V питание.

 С толерантностью разобрались, теперь давайте подключим к контролеру наш модуль, из описания контролера находим нужный нам SPI с ножками FT, им будет SPI2, схема подключения ниже.

Теперь о программе, в ней находятся для работы с модулем три основные функции:
   void send_command(uint8_t com)-отправляет 8бит(команду);
   void send_data(uint8_t *send_data_display)-отправляет массив из 16 данных для отображения;
   uint8_t scan_button(void)-отправляет команду модулю ,ждет возвращения 4байта данных, объединяет их в байт путем битового сдвига и возвращает байт результат;
и еще одна функция:
   void display_data(uint32_t multiplier)-которая получает на вход счет времени из секунд, выделяет часы, минуты и выводит на дисплей. Для вас она будет полезна, так как на ее основе сможете сделать свою функцию для выделения и отображение любых других данных.

#include "stm32f10x.h"
//Устанавливаем начальное время 12 часов, 12ч*60м*60с=43200
uint32_t time=43200;
//Массив наших символы для индикации 1,2,3 и так далее
uint8_t symbol[10]={63,6,91,79,102,109,125,7,127,111};
//Массив для отправки данных
uint8_t send_data_display[16];
void send_command(uint8_t com);
void send_data(uint8_t *send_data_display);
uint8_t scan_button(void);
void display_data(uint32_t multiplier);
void Delay_ms(uint32_t ms);
//Тело нашей программы
int main()
{
//Тактируемся от HSI
RCC_DeInit();
//Настраиваем GPIOВ_Pin_12 для стробирования команд как Output open-drain
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef PIN_Strob;
PIN_Strob.GPIO_Pin = GPIO_Pin_12;
PIN_Strob.GPIO_Speed = GPIO_Speed_10MHz;
PIN_Strob.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &PIN_Strob);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
//Настраиваем GPIOВ_Pin_13(SPI2_SCK) и GPIOВ_Pin_15(SPI2_MOSI) как Alternate function open-drain
GPIO_InitTypeDef SPI2_SCK_MOSI;
SPI2_SCK_MOSI.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15;
SPI2_SCK_MOSI.GPIO_Speed = GPIO_Speed_10MHz;
SPI2_SCK_MOSI.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &SPI2_SCK_MOSI);
//Настраиваем SPI2 как Master и передачу, прием данных по одной линии
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE);
SPI_InitTypeDef SPI2_InitStructure;
SPI2_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI2_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI2_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI2_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI2_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI2_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI2_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
SPI2_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_Init(SPI2, &SPI2_InitStructure);
SPI_Cmd(SPI2, ENABLE);
/*Настраиваем TIM1, предделитель(Prescaler)=200, счетчик таймера(Period)=40000 и того так как тактируемся от HSI частота которого 8Мгерц период(Period) будет 1/8000000*200*40000=1 секунда*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef TIM1_InitStructure;
TIM1_InitStructure.TIM_Period = 40000;
TIM1_InitStructure.TIM_Prescaler = 200-1;
TIM1_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM1_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM1_InitStructure.TIM_RepetitionCounter = 0x0000;
TIM_TimeBaseInit( TIM1, &TIM1_InitStructure);
TIM_ClearFlag( TIM1, TIM_FLAG_Update);
TIM_Cmd( TIM1, ENABLE);
//Основной цикл программы
while(1){
//Отправляем модулю две команды включится и установить автоматический инкремент адреса
   send_command(143);
   send_command(64);
//Отсылаем данные для отображения времени
   display_data(time);
//Прибавляем секунду, проверяем, если отсчитал 24 часа то сбрасываем счетчик времени
   time++;
   if(time==86400){time=0;}
//Останавливаем цикл программы, ждем 1 секунду(переполнения TIM1)
   while(!TIM_GetFlagStatus( TIM1, TIM_FLAG_Update)){}
//Сбрасываем флаг переполнения
   TIM_ClearFlag( TIM1, TIM_FLAG_Update);
//Опрашиваем кнопки модуля для коррекции времени
   while(scan_button()==1){if(time<82801){time+=3600;display_data(time);Delay_ms(400000);}}
   while(scan_button()==2){if(time>3599){time-=3600;display_data(time);Delay_ms(400000);}}
   while(scan_button()==4){if(time<86341){time+=60;display_data(time);Delay_ms(400000);}}
   while(scan_button()==8){if(time>59){time-=60;display_data(time);Delay_ms(400000);}}
}
return 0;
}
//Функция отправки команды
void send_command(uint8_t com){
   GPIO_ResetBits(GPIOB, GPIO_Pin_12);
   SPI_I2S_SendData(SPI2, com);
   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
   GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
//Функция отправки данных(массив) для отображения времени
void send_data(uint8_t *send_data_display){
   GPIO_ResetBits(GPIOB, GPIO_Pin_12);
   SPI_I2S_SendData(SPI2, 192);
   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
   for( uint8_t i=0;i<16;i++){
      SPI_I2S_SendData( SPI2,send_data_display[i]);
      while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == !SET);
   }
   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
   GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
//Функция опрашивает кнопки и возвращаем 8бит о нажатых кнопок
uint8_t scan_button(void){
   uint8_t scan_result;
   GPIO_ResetBits(GPIOB, GPIO_Pin_12);
   SPI_I2S_SendData(SPI2, 66);
   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
   SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Rx);
   while( !SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE));
   scan_result=SPI2->DR;
   while( !SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE));
   scan_result|=SPI2->DR<<1;
   while( !SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE));
   scan_result|=SPI2->DR<<2;
   while( !SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE));
   scan_result|=SPI2->DR<<3;
   GPIO_SetBits(GPIOB, GPIO_Pin_12);
   SPI_BiDirectionalLineConfig( SPI2, SPI_Direction_Tx);
   return scan_result;
}
//Функция высчитывает часы, минуты, секунды и отправляет для отображения времени
void display_data(uint32_t multiplier){
   send_data_display[0]=symbol[multiplier/36000];
   multiplier=multiplier-(multiplier/36000*36000);
   send_data_display[2]=symbol[multiplier/3600];
   multiplier=multiplier-(multiplier/3600*3600);
   send_data_display[6]=symbol[multiplier/600];
   multiplier=multiplier-(multiplier/600*600);
   send_data_display[8]=symbol[multiplier/60];
   multiplier=multiplier-(multiplier/60*60);
   send_data_display[12]=symbol[multiplier/10];
   multiplier=multiplier-(multiplier/10*10);
   send_data_display[14]=symbol[multiplier];
   send_data(send_data_display);
}
//Функция пауза
void Delay_ms(uint32_t ms){ for(uint32_t i=0; i<ms; i++){}}

 Опыт толерантности выводов был, достигнут путем опыта работой с ШИМ, и гибели двух STM32F105RB,
   почтим их память не вставая!


Комментариев нет  Только зарегистрированные пользователи могут оставлять комментарии!