Термометр на STM8L-Discovery

С полгода назад я приобрел платку STM8L-Discovery. К сожалению, на нашем сайте я не нашел простых схем для новичков. Сейчас я сам уже подразобрался во всём и хочу предложить вам интересную, на мой взгляд, поделку. Хочу сказать сразу, что схема может быть перенесена и на другой контроллер (плата ведь у нас отладочная, не охота ее под один лишь девайс использовать). Для этой цели мы можем использовать отладачик нашей платы, далее я опишу процесс переноса прошивки. Для тех, кто лишь начинает работать с STM, хочу сказать — все довольно просто. Для работы использую среду IAR embedded workbench.

Для начала разберемся с датчиком температуры. LM35 — аналоговый датчик, напряжение на выходе которого при 0 по Цельсию равно нулю, а далее возрастает на 10 мВ на градус. То есть напряжение в мВ делим на 10 и получаем температуру датчика.

Теперь разберемся, что такое динамическая индикация. Задача этого метода сократить количество проводов  при работе с несколькими разрядами. Идея заключается в следующем: от каждого разряда выводы соответствующих сегментов собираются вместе, а общие от каждого разряда подключаются отдельно. Далее зажигание происходит следующим образом: подключаются нужные сегменты + общий вывод нужного разряда. И так аналогично с каждым разрядом в цикле. При достаточно быстром переключении глаз не замечает мерцания и мы видим просто многоразрядное число.

Теперь переходим к самому интересному — к контроллеру. На нашей плате стоит МК STM8L152C6T6. Для работы устройства нам потребуется использование таймера и аналогово-цифрового преобразователя (АЦП).

Итак,  таймер нам необходим, чтобы переключать зажигаемые разряды. У нашего МК есть несколько таймеров, но я использую таймер 2 для простоты. Для подключения индикатора я использую порт В под сегменты и выводы 2 и 3 порта D для управления разрядами. Выбор основан на том, что выводы выведены на плате рядом друг с другом. Привожу код инициализации для индикации.

static int ind[2] = { 0xFF,
0xFF, };
char seg = 0;

/*переключение разрядов и сегментов по таймеру*/
#pragma vector=TIM2_OVR_UIF_vector
__interrupt void timer2_interrupt(void)
{
if( !seg )
{
PB_ODR = ind[0];
PD_ODR_bit.ODR2 = 0;
PD_ODR_bit.ODR3 = 1;
seg = 1;
}
else
{
PB_ODR = ind[1];
PD_ODR_bit.ODR2 = 1;
PD_ODR_bit.ODR3 = 0;
seg = 0;
}
TIM2_SR1_bit.UIF = 0;
}

void Init( char priority )
{
PB_DDR = 0xFF;
PB_CR1 = 0xFF;

PD_DDR_bit.DDR2 = 1;
PD_DDR_bit.DDR3 = 1;
PD_CR1_bit.C12 = 1;
PD_CR1_bit.C13 = 1;

CLK_PCKENR1_bit.PCKEN10 = 1; //тактирование подано
TIM2_PSCR = 1;//предделитель частоты
TIM2_ARRH = 0x07;
TIM2_ARRL = 0x07;//уровень переполнения
TIM2_CR1_bit.URS = 1;
TIM2_EGR_bit.UG = 1;
TIM2_IER_bit.UIE = 1;
ITC_SPR5_bit.VECT19SPR = priority;
asm(«RIM»);//глобально разрешим прерывания
TIM2_CR1_bit.CEN = 1;// запустим таймер
}

Далее логично показать код самой индикации.

/*код цифр*/
/*т. к. у меня индикатор с общим анодом, то для зажигания на общий вывод подаю высокий*/
/*потенциал, на сегмент низкий*/
/*каждому горящему сегменту соответствует бит 0, негорящему 1*/
/*биты идут от младшего к старшему в соответствии с сегментами A-E + точка*/
int map[11] =
{
0xC0, //0
0xF9, //1
0xA4, //2
0xB0, //3
0x99, //4
0x92, //5
0x82, //6
0xD8, //7
0x80, //8
0x90, //9
0x00 // error
};

/*пишем цифру в нужный разряд*/
void wrDig( int digit, char pos, bool dp )
{
ind[0] = 0xFF;
ind[1] = 0xFF;
ind[pos] = map[digit];
if ( dp )
ind[pos] &= 0x7F;

}

/*пишем число из 2-х данных цифр*/
void wrNum( int d1, int d0 )
{
ind[0] = map[d0];
if (( d0 > 9 )&&( d0 < 0 ))
ind[0] = map[10];
ind[1] = map[d1];
if (( d1 > 9 )&&( d1 < 0 ))
ind[1] = map[10];
}

/*пишем целое число*/
void wrInt( long int n )
{
int a, b;
if ( n > 99 )
n = n % 100;
a = n % 10;
b = (n-a)/10;
wrNum(b,a);
}

В библиотеке есть ещё функции, но они е используются в проекте и их я не описываю тут; думаю, из их названия понятно их назначение.

Теперь разберемся с АЦП. Именно он преобразует напряжение на выходе датчика в понятный контроллеру цифровой код. Важным параметром является разрешение АЦП — размер результата в битах. Я выбираю 12 бит. Это значит, что при напряжении на входе АЦП, равном опорному ( Vref ) будет результат из 12 двоичных единиц 0x0FFF в шестнадцатиричной системе или 4095 в десятичной.

Код инициализации АЦП

CLK_PCKENR2_bit.PCKEN20 = 1; //тактирование
ADC1_CR1_bit.ADON = 1; //включим преобразователь
ADC1_SQR1_bit.DMAOFF = 1; //вырубим контроллер DMA
ADC1_SQR4_bit.CHSEL_S2 = 1; //второй канал — пин 4 порта А
ADC1_TRIGR4_bit.TRIG2 = 1;
ADC1_CR2_bit.SMTP1=7;
ADC1_TRIGR1_bit.TSON = 1; //включим внутренний датчик температуры

Теперь завершающий штрих — все выше написанное связать воедино.

float value;
int middle_value;
int res[BUF_SIZE];

/* настройка пинов для светодиода и кнопки*/
/*кнопка на пине С1*/
PC_DDR_bit.DDR1 = 0; //на вход
PE_DDR_bit.DDR7 = 1;//push-pull режим
PC_CR1_bit.C11 = 1;//разрешить прерывания пином
/*зеленый светодиод на пине Е7*/
PE_CR1_bit.C17 = 1;//на выход
PC_CR2_bit.C21 = 1;
PE_ODR_bit.ODR7 = 1;//подать на выход 1
EXTI_CR1_bit.P1IS = 2;//прерывание от кнопки по спаду
asm( «RIM» );


 

В итоге имеем следующее устройство.

Схема для тех, кто будет делать на отдельной плате. Распиновка контроллера STM8L152C6T6

Если собираете на макетке, то просто подключаете к нужным выводам платы нужные проводники.

Оно умеет мерить температуру датчика и контроллера. Переключение по нажатию кнопки, при работе внешнего датчика горит зеленый светодиод.

Как я уже говорил, можно перенести прошивку на внешний контроллер. Для этого к чипу подключаем питание и делаем выводы от пинов RESET и SWIM. В проекте не забываем поменять настройки и заголовочные файлы, если используем не STM8L52C6. Далее справа над LCD снимаем 2 джампера. Слева видим штыревые контакты, 4 штуки. К2 втором сверху подключаем вывод SWIM, к четвертому RESET от внешнего кристалла. И шьем.

Мой профиль на форуме

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.