Для управления семисегментными индикаторами нам понадобятся всего 3 вывода (4, 7, 8):
LATCH_DIO 4 - разрешение записи в регистр (LOW)
CLK_DIO 7 - синхронизация
DATA_DIO 8 - данные (последовательно, побитно)
Данные будут передаваться двумя байтами. Первый - значение индикатора, второй - адрес индикатора. Передача производится слева направо. Индикаторы принимают значения от 0 до 9 - {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}
адрес принимает вид {0xF1,0xF2,0xF4,0xF8}
Принципиальная электрическая схема
Очень похоже на работу SPI не правда ли? Поэтому для отображения цифр на семисегментных индикаторах будем использовать периферийное устройство SPI1 в составе STM32. Ниже представлен код программы который позволяет отобразить на индикаторе цифры 1234.
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//LATCH_DIO - разрешение записи в регистр (LOW)
GPIO_InitTypeDef latch;
latch.GPIO_Speed = GPIO_Speed_2MHz;
latch.GPIO_Mode = GPIO_Mode_Out_PP;
latch.GPIO_Pin = GPIO_Pin_8 ;
GPIO_Init(GPIOA, &latch);
//выводы под SPI CLK_DIO - GPIO_Pin_5, DATA_DIO - GPIO_Pin_7
GPIO_InitTypeDef gpio;
gpio.GPIO_Speed = GPIO_Speed_2MHz;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_Init(GPIOA, &gpio);
// настраиваем SPI1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitTypeDef spi;
spi.SPI_Direction = SPI_Direction_1Line_Tx;
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_DataSize = SPI_DataSize_16b;
spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
spi.SPI_CPHA = SPI_CPHA_1Edge; //фронт синхронизации
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
spi.SPI_FirstBit = SPI_FirstBit_MSB; //передавать сначала младший бит
spi.SPI_CRCPolynomial = 15;
SPI_Init(SPI1, &spi);
SPI_Cmd(SPI1, ENABLE);
while(1)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
SPI_I2S_SendData(SPI1, 0xC0F1);// пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
SPI_I2S_SendData(SPI1, 0xF9F2);// пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
SPI_I2S_SendData(SPI1, 0xA4F4);// пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);// регистр TX пустой?
SPI_I2S_SendData(SPI1, 0xB0F8);// пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);// ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8);// делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
}
}
А тут код термометра. Отображает на индикаторах температуру до сотых долей градуса Цельсия.
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_adc.h"
//значение цифр от 0 до 9
int number[]={0xC000,0xF900,0xA400,0xB000,0x9900,0x9200,0x8200,0xF800,0x8000,0x9000};
//номер индикатора
int indicator[]={0xF1,0xF2,0xF4,0xF8};
int i;
int value;
float temperature = 0.0; //температура в градусах цельсия
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//LATCH_DIO - разрешение записи в регистр (LOW)
GPIO_InitTypeDef latch;
latch.GPIO_Speed = GPIO_Speed_2MHz;
latch.GPIO_Mode = GPIO_Mode_Out_PP;
latch.GPIO_Pin = GPIO_Pin_8 ;
GPIO_Init(GPIOA, &latch);
//выводы под SPI CLK_DIO - GPIO_Pin_5, DATA_DIO - GPIO_Pin_7
GPIO_InitTypeDef gpio;
gpio.GPIO_Speed = GPIO_Speed_2MHz;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_Init(GPIOA, &gpio);
// настраиваем SPI1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitTypeDef spi;
spi.SPI_Direction = SPI_Direction_1Line_Tx;
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_DataSize = SPI_DataSize_16b;
spi.SPI_CPOL = SPI_CPOL_Low; //полярность сигнала синхронизации
spi.SPI_CPHA = SPI_CPHA_1Edge; //фронт синхронизации
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
spi.SPI_FirstBit = SPI_FirstBit_MSB; //передавать сначала младший бит
spi.SPI_CRCPolynomial = 15;
SPI_Init(SPI1, &spi);
SPI_Cmd(SPI1, ENABLE);
//настраиваем градусник
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_InitTypeDef term;
term.ADC_Mode = ADC_Mode_Independent;
term.ADC_ScanConvMode = DISABLE;
term.ADC_ContinuousConvMode = ENABLE;
term.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
term.ADC_DataAlign = ADC_DataAlign_Right;
term.ADC_NbrOfChannel = 1;
ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 1, ADC_SampleTime_239Cycles5);
ADC_Init (ADC1, &term);
ADC_TempSensorVrefintCmd(ENABLE);
ADC_Cmd (ADC1, ENABLE);
ADC_ResetCalibration(ADC1); //Сброс калибровочных данных
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1); //Новая калибровка
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_Cmd (ADC1, ENABLE);
while(1)
{
for (i=0;i<5000;i++) //чтобы слишком часто не обновлять информацию на индикаторах
{
value = temperature/10; //вычисляем значение первого знакоместа
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // регистр TX пустой?
SPI_I2S_SendData(SPI1, number[value]+indicator[0]); // пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); // ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8); // делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
value = temperature-(value*10); //вычисляем значение второго знакоместа
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // регистр TX пустой?
SPI_I2S_SendData(SPI1, (number[value]+indicator[1])-0x8000); // пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); // ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8); // делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
value = temperature; //вычисляем значение третьего знакоместа
value = (temperature*10)-(value*10);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // регистр TX пустой?
SPI_I2S_SendData(SPI1, number[value]+indicator[2]); // пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); // ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8); // делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
value = temperature*10; //вычисляем значение четвертого знакоместа
value = (temperature*100)-(value*10);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // регистр TX пустой?
SPI_I2S_SendData(SPI1, number[value]+indicator[3]); // пишем в TX данные, начало передачи
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); // ждём окончания передачи
GPIO_ResetBits(GPIOA, GPIO_Pin_8); // делаем перепад на LATCH_DIO
GPIO_SetBits(GPIOA, GPIO_Pin_8);
}
temperature = (1750 - ADC_GetConversionValue(ADC1)) / 4.3 + 25; // результат в градусах Цельсия
}
}