Главная » Статьи » Proton PICBasic |
Возьмем случай более сложный, нежели простое отображение часов и минут, мы будем отображать также и секунды и сотые доли секунды. Получаем секундомер. О! Пусть это будет секундомер. Кроме того, мы подключим индикаторы к порту микроконтроллера не как обычно, а произвольно. Для этого мы воспользуемся специальным инструментом. Таким образом, нам потребуется 8 ножек микроконтроллера для вывода цифр на индикаторы. Мы их запараллелим, поскольку индикация и называется динамической потому, что мы будем динамично переключать каналы управления, меняя только выводимую для каждого отдельного индикатора цифру в определенный момент. Также нам понадобятся еще 8 портов для управления общими анодами (или катодами) индикаторов. Уже 16! Кроме этого, нам требуются входы для кнопок, которыми мы будем запускать, останавливать и сбрасывать время. Сделаем их отдельными входами. Итого – 18 портов. Не будем заморачиваться и возьмем PIC16F877. Индикаторы – с общим анодом – значит зажигать сегменты будем нулем, подавая на общий анод единицу. Итак, рисуем схему: Обратите внимание? Как подключены сегменты. Все мы привыкли подключать индикатор к порту последовательно – сегмент A – к, например PORTB.0, сегмент B – к PORTB.1 и так далее. Будем считать, что нам необходимо для лучшей разводки платы подключить по другому. Например, как на схеме. Как у меня так получилось? Я воспользовался созданным мной ранее этим онлайн-инструментом. Там все просто, обратите внимание на рисунок: Подключаем порты микроконтроллера, щелкая по названию соответствующего порта. Порты подключаются последовательно, то есть, сначала нам нужно подцепить какой-нибудь порт к сегменту A, затем следующий – к сегменту B и так далее. Думаю, все понятно. Code '-------------------------- Описание проекта --------------------------------- 'Проект : Динамическая индикация 'Автор : Admin ' 'Версия : 1.0.0 от 21.10.2011 ' '-------------------------- Опции компилятора -------------------------------- Declare SHOW_SYSTEM_VARIABLES = OFF ' При симуляции в Proteus не показывать внутренние переменные Declare FSR_CONTEXT_SAVE = On ' Заботиться о сохранении содержимого регистра FSR Declare Reminders = OFF ' Выключить напоминания компилятора Declare Warnings = OFF ' Выключить предупреждения компилятора Declare Optimiser_Level 0 ' Выключить оптимизацию программы Declare Bootloader = OFF ' Выключить загрузчик ;-------------------------- Общие настройки----------------------------------- Device = 16F877 ' Используемый микроконтроллер Xtal = 4 ' Частота осциллятора 4 МГц '-------------------------- Конфигурация программирования -------------------- Config CP_OFF, DEBUG_OFF, CPD_OFF, LVP_OFF, BODEN_OFF, PWRTE_ON, WDT_OFF, XT_OSC '-------------------------- Настройки портов --------------------------------- PortB_Pullups = OFF ' Выключить подтягивающие резисторы на PORTB Declare All_Digital = On ' Установить все порты цифровыми входами/выходами '-------------------------- Регистры специального назначения------------------ '-------------------------- INTCON ------------------------------------------- Symbol RBIF = INTCON.0 ' Флаг внешнего прерывания по PORTB.4-PORTB.7 Symbol INTF = INTCON.1 ' Флаг внешнего прерывания по PORTB.0(INT) Symbol T0IF = INTCON.2 ' Флаг переполнения TMR0 Symbol RBIE = INTCON.3 ' Бит разрешения прерывания по PORTB.4-PORTB.7 Symbol INTE = INTCON.4 ' Бит разрешения прерывания по PORTB.0(INT) Symbol T0IE = INTCON.5 ' Бит разрешения прерывания по переполнению TMR0 Symbol PEIE = INTCON.6 ' Бит разрешения прерывания от периферийных устройств Symbol GIE = INTCON.7 ' Бит глобального разрешения прерываний '-------------------------- PIE1, PIR1 --------------------------------------- Symbol TMR1IE = PIE1.0 ' Бит разрешения прерывания по переполнению TMR1 Symbol TMR1IF = PIR1.0 ' Флаг прерывания по переполнению TMR1 '-------------------------- T1CON -------------------------------------------- Symbol TMR1ON = T1CON.0 ' Бит включения модуля TMR1 Symbol TMR1CS = T1CON.1 ' Выбор источника тактового сигнала для TMR1 Symbol NOT_T1SYNC = T1CON.2 ' Синхронизация внешнего тактового сигнала Symbol T1INSYNC = T1CON.2 ' Синхронизация внешнего тактового сигнала Symbol T1SYNC = T1CON.2 ' Синхронизация внешнего тактового сигнала Symbol T1OSCEN = T1CON.3 ' Включение тактового генератора TMR1 Symbol T1CKPS0 = T1CON.4 ' Выбор коэффициента деления предделителя TMR1 Symbol T1CKPS1 = T1CON.5 ' Выбор коэффициента деления предделителя TMR1 '-------------------------- ADCON0 ------------------------------------------- Symbol ADON = ADCON0.0 ' Включение модуля АЦП Symbol NOT_DONE = ADCON0.2 ' Статус модуля АЦП Symbol GO_DONE = ADCON0.2 ' Статус модуля АЦП Symbol CHS0 = ADCON0.3 ' Выбор аналогового канала Symbol CHS1 = ADCON0.4 ' Выбор аналогового канала Symbol CHS2 = ADCON0.5 ' Выбор аналогового канала Symbol ADCS0 = ADCON0.6 ' Выбор источника тактового сигнала Symbol ADCS1 = ADCON0.7 ' Выбор источника тактового сигнала '-------------------------- ADCON1 ------------------------------------------- Symbol PCFG0 = ADCON1.0 ' Настройка каналов АЦП Symbol PCFG1 = ADCON1.1 ' Настройка каналов АЦП Symbol PCFG2 = ADCON1.2 ' Настройка каналов АЦП Symbol PCFG3 = ADCON1.3 ' Настройка каналов АЦП Symbol ADFM = ADCON1.7 ' Формат результата преобразования '-------------------------- Определение переменных --------------------------- Dim MSEKED As Byte 'единицы миллисекунд Dim MSEKDES As Byte 'десятки миллисекунд Dim SEKED As Byte 'единицы секунд Dim SEKDES As Byte 'десятки секунд Dim MINED As Byte 'единицы минут Dim MINDES As Byte 'десятки минут Dim CHASED As Byte 'единицы часов Dim CHASDES As Byte 'десятки часов Dim INDEX As Byte 'индекс для отображения Dim StartFlag As Bit 'Флаг, указывающий на то, запущен секундомер или нет '-------------------------- Определение символов ----------------------------- Symbol RESET_ = PORTC.1 'Кнопка сброса Symbol SF = PORTC.0 'Кнопка старта/останова Symbol SEGMENTS = PORTB 'Назовем порт, отвечающий за вывод сегментов Symbol Anodes = PORTD Symbol DOT = PORTB.4 '-------------------------- Начало ------------------------------------------- TRISA = %00000000 'Порт А - на выход TRISB = %00000000 'Порт Б - на сегменты TRISC = %00000011 'Порт С - на кнопки TRISD = %00000000 'Порт Д - управление анодами SEGMENTS = %00010001 'Зажгем все нули Anodes = %11111111 'Включим все индикаторы StartFlag = 0 '-------------------------- ADCON0, ADCON1 ----------------------------------- 'Все каналы - цифровые порты ввода/вывода ADCON0 = %0000000 ' Значение регистра ADCON0 ADCON1 = %10000111 ' Значение регистра ADCON1 '-------------------------- Настройка TMR1 для прерываний -------------------- TMR1L = $F0 ' Значение младшего регистра TMR1 TMR1H = $D8 ' Значение старшего регистра TMR1 T1CON = %00000000 TMR1IE = 1 ' Разрешение прерывания при переполнении TMR1 с частотой 10,000000 Гц PEIE = 1 ' Разрешение прерываний от периферийных устройств GIE = 1 ' Разрешение глобального прерывания On_Interrupt GoTo ISR_Service TMR1ON = 1 'Запустим таймер GoTo MainProgram '-------------------------- Прерывания-------------------------- ISR_Service: Context Save ' Этой строкой компилятор автоматически сохранит регистры Status и W ' во временные переменные Nop ' Подстроим ход часов TMR1L = $ED ' Зададим значение младшего регистра TMR1, с учетом сохранения контекста TMR1H = $D8 ' Значение старшего регистра TMR1 If StartFlag = 1 Then 'Если разрешен старт, Inc MSEKED 'то инкрементируем десятки миллисекунд EndIf If MSEKED = 10 Then 'Если десятки миллисекунд дошли до сотни(10 раз по 10 мсек), то MSEKED = 0 'обнуляем их Inc MSEKDES 'и увеличиваем сотни миллисекунд If MSEKDES = 10 Then ' Если прошла 1000 миллисекунд (10 раз по 100 мсек) MSEKDES = 0 ' обнуляем их Inc SEKED ' и прибавляем секунды If SEKED = 10 Then 'Если прошло десять секунд, SEKED = 0 'то сбрасываем их Inc SEKDES 'и прибавляем один десяток секунд If SEKDES = 6 Then 'Если прошло 60 секунд, SEKDES = 0 'то обнуляем Inc MINED 'Инкрементируем единицы минут If MINED = 10 Then 'Если прошло 10 минут, MINED = 0 'то обнуляем Inc MINDES 'Прибавляем десятки минут If MINDES = 6 Then 'Если прошло 60 минут, MINDES = 0 'обнуляем Inc CHASED 'Увеличиваем на 1 единицы часов If CHASED = 10 Then 'Если прошло 10 часов, CHASED = 0 'обнуляем Inc CHASDES 'и прибавляем десятки часов If CHASDES = 9 Then 'Если прошло 90 часов, CHASDES = 0 'обнуляем 'Думаю, до такого времени у секундомера никто не будет сидеть <img src="http://s8.ucoz.net/sm/24/smile.gif" border="0" align="absmiddle" alt="smile" /> 'Здесь можно придумать что-нибудь свое 'это вам домашнее задание EndIf EndIf EndIf EndIf EndIf EndIf EndIf EndIf TMR1IF = 0 'Сбросим флаг, вызвавший прерывание Context Restore ' Возврат из обработчика прерывания и восстановление 'регистров Status и W '-------------------------- Главная программа ------------------------- MainProgram: Anodes = %10000000 'Зажигаем анод первого индикатора INDEX = MSEKED 'Загружаем значение десятков миллисек GoSub OutNum 'Выставляем в порт GoSub Dlay 'Ждем для того, чтобы различить цифру Anodes = %01000000 'Зажигаем анод второго индикатора INDEX = MSEKDES 'Сотни миллисекунд GoSub OutNum GoSub Dlay Anodes = %00100000 'Третий индикатор INDEX = SEKED 'Единицы секунд GoSub OutNum DOT = 0 'Зажгем точку, чтобы визуально отделить секунды от миллисекунд GoSub Dlay Anodes = %00010000 'Четвертый индикатор INDEX = SEKDES 'Десятки секунд GoSub OutNum GoSub Dlay Anodes = %00001000 'Зажигаем пятый индикатор INDEX = MINED 'Загружаем единицы минут GoSub OutNum DOT = 0 'Зажигаем точку, чтобы отделить минуты от секунд GoSub Dlay Anodes = %00000100 'Шестой индикатор INDEX = MINDES 'Десятки минут GoSub OutNum GoSub Dlay Anodes = %00000010 'Седьмой индикатор INDEX = CHASED 'Единицы часов GoSub OutNum DOT = 0 'Зажгем точку, чтобы отделить часы от минут GoSub Dlay Anodes = %00000001 'Восьмой индикатор INDEX = CHASDES 'и десятки часов GoSub OutNum GoSub Dlay If StartFlag = 0 Then 'Если секундомер остановлен, то If RESET_ = 0 Then 'Если нажата кнопка сброса, обнуляем все цифры MSEKED = 0 MSEKDES = 0 SEKED = 0 SEKDES = 0 MINED = 0 MINDES = 0 CHASED = 0 CHASDES = 0 INDEX = 0 EndIf EndIf If SF = 0 Then 'Если нажата кнопка Старт/стоп, то StartFlag = ~StartFlag 'выставляем флаг либо старта, либо стопа While SF = 0 'Ждем отпускания кнопки SEGMENTS = %11111110 'На время нажатия показываем заставку Anodes = %11111111 Wend EndIf GoTo MainProgram ' Возврат на начало основной программы OutNum: SEGMENTS = LookUp INDEX,[$11, $9F, $58, $1C, $96, $34, $30, $1F, $10, $14] 'Здесь по порядковому номеру INDEX мы загружаем в порт число из квадратных скобок Dlay: DelayMS 2 'Задержка для отображения Return Работает она так – a фоновом режиме запущен таймер TMR1, который настроен на переполнение через каждые 10 миллисекунд. Каждое переполнение таймера вызывает прерывание (за обработку прерываний отвечает подпрограмма ISR_Service), в котором мы загружаем таймер новым значением, чтобы он опять отсчитывал новые 10 миллисекунд. В обработчике прерываний мы инкрементируем наш секундомер, если он запущен, каждые 10 миллисекунд,. Обратите внимание на значения, которые загружаются в таймер (TMR1H и TMR1L), а также на команду Nop, которая сама по себе ничего не делает, но дает задержку в один машинный цикл. Эти значения таймера, а также команда Nop подобраны экспериментальным путем с помощью отладки в MPLAB. К статье прилагаю архив, содержащий все материалы. Вы можете скачать его и запустить проект MPLAB. Как писать программы с помощью MPLAB на Basic? Я писал раньше – в этой статье.
Похожие материалы: Часы на МК PIC16F628A с двумя таймерами, ЧАСЫ НА PIC16F628 С ДАТОЙ И ДНЕМ НЕДЕЛИ | |||
Просмотров: 15554 | Комментарии: 7 | | |
Всего комментариев: 7 | ||||||||
| ||||||||