- •Упражнение a - простой стек
- •Упражнение b - стек с обработкой ошибок
- •Упражнение c - стек без ограничения на размер
- •Очередь
- •Упражнение d - простая очередь
- •Упражнение e - очередь с обработкой ошибок
- •Упражнение f - очередь без ограничений на размер
- •Упражнение g - простой дек
- •Упражнение h - дек с обработкой ошибок
- •Динамическая индикация.
- •Stm32 с нуля. Таймеры. Генерация шим.
- •Матричная клавиатура
Динамическая индикация.
Схемотехника
Для
вывода часто применяют светодиодные
индикаторы. Выводить информацию на них
можно как статически, так и динамически.
Дальше я попробую в картинках показать
какие виды динамической индикации
бывают и как она вообще работает.
1.
Статическая индикация.
Самый
простой вид индикации — статический.
При ее использовании каждый сегмент
индикатора постоянно находится в одном
из двух состояний — включен или выключен.
Ее основное достоинство в том, что после
вывода информации, например в сдвигающий
регистр, состояние индикатора не
изменится пока не будут изменены данные
в этих регистрах. Так же т.к. напряжение
на сегментах присутствует постоянно
яркость индикатора будет максимальной.
Кроме этих двух плюсов есть также два
больших минуса. Во первых требуется
большое число регистров (один разряд —
одна микросхема), нужна куча резисторов
— по одному на каждый сегмент. Можно
конечно поставить специальные драйверы
(что-то вроде mbi5026), которым резисторы
не нужны и выходов и них больше (аж 16
штук), но они стоят денег. И во вторых
все сборки, в которых от 3 и больше
разрядов, идут с соединенными сегментами
и статически их использовать просто не
получится. Да и разводить все это дело
на плате дело нудное и не интересное.
Поэтому
перейдем к динамической индикации.
2.
Динамическая индикация.
При
динамической индикации сегменты
зажигается по очереди. А за счет инерции
глаза кажется, что индикатор горит
постоянно. Из ее основных плюсов —
требуется гораздо меньше внешних
элементов. Основной минус — для нее
постоянно требуется внимание процессора:)
Частота смены сегментов выбирается
обычно не ниже 50Гц. Лучше использовать
частоты не кратные 50, иначе при
искусственном освещении может появиться
мерцание. Частота прерываний считается
как «Кол-во разрядов» х «Частота
обновления». Так для 8 разрядов с частотой
60Гц нужно вызывать прерывание с
F=8х60=480Гц.
Есть два вида такой индикации
— поразрядная и посегментная. Первая
наиболее известна и популярна, вторая
лучше подходит когда нужно большое
количество разрядов (больше 10).
Touchscreen.
Се́нсорный экран — устройство ввода информации, представляющее собой экран, реагирующий на прикосновения к нему.
Таймеры, генерация ШИМ.
Stm32 с нуля. Таймеры. Генерация шим.
Posted on 19.01.2013
В прошлой статье (вот тут) мы рассмотрели в общих чертах таймеры в STM32 и написали простенькую программку. Теперь, как и обещал, поподробнее покопаем генерацию ШИМ при помощи все того же таймера TIM4.
Итак…
Честно говоря, писать то особо нечего) Думаю многие знают что такое ШИМ и с чем его едят, а если нет то об этом можно прочитать, например, в Википедии, так что нет, наверное, смысла отдельно описывать то, что уже многократно и хорошо описано =) Давайте писать пример для генерации ШИМ. Просто замутить такой сигнал не так интересно, так что давайте хоть немного усложним задачу. Будем генерировать ШИМ с разным заполнением в зависимости от состояния кнопки. Если кнопка нажата – генерируем сигнал с периодом 2.5 мс и заполнением 1.5 мс, а если кнопка не нажата – то период – 2.5 мс, заполнение – 0.5 мс. Ничего сложного )
Так что создаем новый проект и пишем код. Для начала набор includ’ов:
#include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_tim.h" |
Добавили все файлы, необходимые нам для работы. Объявим переменные:
#define TIMER_PRESCALER 720 #define EXT_TIM_PULSE 150 #define TIM_PULSE 50 |
TIMER_PRESCALER мы уже упоминали — это предделитель частоты. EXT_TIM_PULSE – увеличенная длительность заполнения (то есть при нажатой кнопке), аналогично TIM_PULSE – обычная длительность (кнопка не нажата). Продолжаем:
uint16_t previousState; GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM; uint16_t buttonPreviousState; |
Просто переменные, которые нам понадобятся в проекте. Пока все понятно )
И вот наконец-то кое-что поинтереснее, а именно наша разросшаяся функция initAll ().
void initAll() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = GPIO_Pin_6; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &port);
port.GPIO_Mode = GPIO_Mode_IPD; port.GPIO_Pin = GPIO_Pin_3; port.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &port);
TIM_TimeBaseStructInit(&timer); timer.TIM_Prescaler = TIMER_PRESCALER; timer.TIM_Period = 250; TIM_TimeBaseInit(TIM4, &timer);
TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = 50; timerPWM.TIM_OCMode = TIM_OCMode_PWM1; timerPWM.TIM_OutputState = TIM_OutputState_Enable; TIM_OC1Init(TIM4, &timerPWM); } |
Давайте прямо по строчкам смотреть, что же тут написано. Ну, вначале уже привычное включение тактирования необходимой периферии. Шестую ножку порта GPIOB настраиваем на работу в режиме альтернативной функции(!). Лезем в даташит на контроллер и видим, что альтернативной функцией у этого вывода является первый канал таймера TIM4. То что надо )
Вывод PA3 настраиваем на вход – там будет наша воображаемая кнопка. Почему именно третья ножка? Да фиг его знает, просто так ) Итак, с инициализацией портов закончили, идем настраивать таймер. Поначалу все конфигурируем, как и в предыдущем проекте. А вот дальше что-то новенькое:
TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = 50; timerPWM.TIM_OCMode = TIM_OCMode_PWM1; timerPWM.TIM_OutputState = TIM_OutputState_Enable; TIM_OC1Init(TIM4, &timerPWM); |
Для использования режима генерации ШИМ нам понадобилась структура TIM_OCInitTypeDef. Поле TIM_Pulse – длительность заполнения, пусть будет сначала 50 тиков (0.5 мс). Далее задаем режим — TIM_OCMode_PWM1. Помимо PWM1 есть еще PWM2. Это всего лишь разные режимы ШИМ – с выравниванием по границе и по центру. В поле TIM_OutputState забиваем – Enable и инициализируем таймер. Готово!
Осталось немного ) Функция main() – как же без нее:
int main() { __enable_irq (); initAll(); buttonPreviousState = 0; TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); TIM_Cmd(TIM4, ENABLE); NVIC_EnableIRQ(TIM4_IRQn); while(1) { __NOP(); } } |
Все, как и раньше – включаем прерывание по переполнению. Оно нам нужно, чтобы опрашивать кнопку именно в момент окончания периода ШИМ. Вот и сам код обработчика:
void TIM4_IRQHandler() { uint16_t button = 0; button = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3); TIM_ClearITPendingBit(TIM4, TIM_IT_Update); if ((button == 1) && (buttonPreviousState == 0)) { TIM4->CCR1 = EXT_TIM_PULSE; buttonPreviousState = 1; } if ((button == 0) && (buttonPreviousState == 1)) { TIM4->CCR1 = TIM_PULSE; buttonPreviousState = 0; } } |
Опрашиваем кнопку, ничего нового, знакомая функция ) Возможно возникнет вопрос – зачем так извращаться «(button == 1) && (buttonPreviousState == 0)» ? А чтобы работа с регистром таймера шла не на каждое прерывание, а только когда состояние кнопки изменяется. Упомянутая работа с регистром заключается в прямой записи длительности заполнения в регистр таймера TIM_CCR.
Компилируем,
идем в отладчик, запускаем программу и
эмулируем нажатие кнопки на PA3. Если кто
забыл, открываем окно General
Purpose I/O A (GPIOA) и
вручную выставляем бит на входе PA3, то
есть говорим контроллеру, что кнопка
типа нажата, давай действуй =) В окошке
логического анализатора видим:
При
изменении состояния кнопки меняется и
скважность импульсов, как и задумывалось
) Ура, товарищи!
ЦАП.
Цифро-аналоговый преобразователь (ЦАП) — устройство для преобразования цифрового (обычно двоичного) кода в аналоговый сигнал (ток, напряжение или заряд). Цифро-аналоговые преобразователи являются интерфейсом между дискретным цифровым миром и аналоговыми сигналами.
Аналого-цифровой преобразователь (АЦП) производит обратную операцию.
Звуковой ЦАП обычно получает на вход цифровой сигнал в импульсно-кодовой модуляции (англ. PCM, pulse-code modulation). Задача преобразования различных сжатых форматов в PCM выполняется соответствующими кодеками.
АЦП.
Аналого-цифровой преобразователь[1][2][3] (АЦП, англ. Analog-to-digital converter, ADC) — устройство, преобразующее входной аналоговый сигнал в дискретный код (цифровой сигнал).
Обратное преобразование осуществляется при помощи цифро-аналогового преобразователя (ЦАП, DAC).
Как правило, АЦП — электронное устройство, преобразующее напряжение в двоичный цифровой код. Тем не менее, некоторые неэлектронные устройства с цифровым выходом следует также относить к АЦП, например, некоторые типы преобразователей угол-код. Простейшим одноразрядным двоичным АЦП является компаратор.
ОЗУ.
Операти́вная па́мять (англ. Random Access Memory, RAM, память с произвольным доступом; ОЗУ (оперативное запоминающее устройство); комп. жарг. память, оперативка) — энергозависимая часть системы компьютерной памяти, в которой во время работы компьютера хранится выполняемый машинный код (программы), а также входные, выходные и промежуточные данные, обрабатываемые процессором.
Обмен данными между процессором и оперативной памятью производится:
непосредственно;
через сверхбыструю память 0-го уровня — регистры в АЛУ, либо при наличии аппаратного кэша процессора — через кэш.
Содержащиеся в современной полупроводниковой оперативной памяти данные доступны и сохраняются только тогда, когда на модули памяти подаётся напряжение. Выключение питания оперативной памяти, даже кратковременное, приводит к искажению либо полному разрушению хранимой информации.
ПЗУ.
Постоя́нное запомина́ющее устро́йство (ПЗУ) — энергонезависимая память, используется для хранения массива неизменяемых данных.
Инкрементальный энкодер.
Энкодер это всего лишь цифровой датчик угла поворота, не более того. Энкодеры бывают абсолютные — сразу выдающие двоичный код угла и инкрементальные, дающие лишь указание на направление и частоту вращения, а контроллер, посчитав импульсы и зная число импульсов на оборот, сам определит положение.
Импульсный (пошаговый) энкодер относится к типу энкодеров, которые предназначены для указания направления движения и/или углового перемещения внешнего механизма. Пошаговый энкодер формирует импульсы, количество которых соответствует повороту вала на определенный угол. Этот тип энкодеров, в отличие от абсолютных, не формирует код положения вала, когда вал находится в покое. Пошаговый энкодер связан со счетным устройством, это необходимо для подсчета импульсов и преобразования их в меру перемещения вала. Пошаговый оптический энкодер состоит из следующих компонентов: источника света, диска с метками, фототранзисторной сборки и схемы обработки сигнала. Диск пошагового энкодера подразделен на точно позиционированные отметки. Количество отметок определяет количество импульсов за один оборот. К примеру, если диск поделен на 1000 меток, тогда за 250 импульсов вал должен повернуться на 90 градусов.
Диск с метками инкрементного энкодера
Матрица кнопок.
