С полгода назад я приобрел платку 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; } /*пишем число из двух данных цифр*/ 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 от внешнего кристалла. И шьем.
Прикрепленные файлы:
- Градусник.zip (4 Кб)
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация