2 Управление таймер-счетчиками
Задание. Мигать попеременно светодиодами D1, D2 и D3. Время горения светодиода в два раза больше чем время простоя. При нажатии кнопки загораются D5 и D8. Организовать мигание с помощью прерываний от таймера..
Ниже приведен код, который будет управлять таймер-счетчикам микроконтроллера.
#include <xc.h>
#define _XTAL_FREQ 4000000
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up
//Timer is enabled)
#pragma config CP = OFF // Code Protection bit (Code protection disabled)
unsigned char result=1;
unsigned int TIM0_count=0;
void CheckButton(void)// ф-ция опроса кнопки
{
unsigned int butcount=0;
while(!RA2)
{
if(butcount < 10000)
{
butcount++;
}
else
{PORTB=0; // погашение всех светодиодов
TIM0_count=0;//сброс счетчика по таймеру, чтоб начать с начала
if (result == 0)result = 1; else result = 0;// изменение режима
/* переключение режима: result = 0 – мигают D5, D7, result = 1 – мигают D1, D2, D3 */
break;
}
}
}
void interrupt timer0()
{
if (result) // до нажатия кнопки
switch(TIM0_count/10) // пауза через 10 отсчётов таймера
{
case 0:
PORTBbits.RB1 = 1; // Вкл D1
break;
case 2:// не 1 а 2 10 отсчетов пропускаем – горит в 2 раза дольше
PORTBbits.RB1 = 0; // Выкл D1
break;
case 3:
PORTBbits.RB2 = 1; // Вкл D2
break;
case 5: // 10 отсчетов пропускаем – горит в 2 раза дольше
PORTBbits.RB2 = 0; // Выкл D2
break;
case 6:
PORTBbits.RB3 = 1; // аналогично
break;
case 8:
PORTBbits.RB3 = 0;
break;
case 9:
TIM0_count=0; /*сброс счетчика таймера после погасания D3 через 10 отсчетов*/
break;
}
if (!result) // после нажатия кнопки
switch(TIM0_count/10)
{
case 0:
PORTBbits.RB5 = 1; // Вкл D5
break;
case 2: // 10 отсчетов пропускаем – горит в 2 раза дольше
PORTBbits.RB5 = 0; // Выкл D2
break;
case 3:
PORTBbits.RB7 = 1;
break;
case 5: // 10 отсчетов пропускаем – горит в 2 раза дольше
PORTBbits.RB7 = 0;
break;
case 7:
TIM0_count=0; /*сброс счетчика таймера после погасания D3 через 10 отсчетов*/
break;
}
TIM0_count++;/*увеличение счетчика таймера */
T0IF=0;// сброс флага прерывания
}
void main(void) {
TRISB = 0x00; // Все выводы настраиваем порта B как выход
PORTB = 0x00; // гасим все светодиоды
TRISA &= ~0x03;// Порт А2 – на вход
PORTA &= ~0x03; /* подключен внутренний подтягивающий резистор на порт А2*/
OPTION_REG=0x07; /* включает биты 0,1 и 2 — это биты предделителя, используется деление частоты максимальное — на 256*/
INTCON=0xA0; /* включаются глобальные прерывания и прерывания от таймера, установкой в 1 биты 7 и 5 регистра INTCON*/
TMR0=0;/* заносится 0 в регистр счѐта таймера, тем самым запустится
таймер. */
while(1)
{CheckButton(); // опрос кнопки постоянно
}
return;
}
3 Управлять семисегментными индикаторами
Задание. Выполнить отсчет времени от 2500 до 1500, с шагом 50. Частота смены 1 Гц.
Ниже приведен код, который будет управлять сегментным индикатором.
#include <xc.h>
#define _XTAL_FREQ 4000000
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF /* Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for
programming)*/
#pragma config CPD = OFF /*Data EEPROM Memory Code Protection bit
(Data EEPROM code protection off)*/
#pragma config WRT = OFF /* Flash Program Memory Write Enable bits
(Write protection off; all program memory may be written to by EECON control)*/
#pragma config CP = OFF /*Flash Program Memory Code Protection bit
(Code protection off)*/
//------------------------------------------------------------
unsigned int i=2500,j,k,digit[4],TIM0_count=0,upd=0; /* глобальные переменные*/
//--------------------------------------------------------------
void segchar (unsigned char seg) /* функция отображения цифр 0-9 на индикаторах*/
{
switch (seg)
{
case 1:
PORTD = ~0b11111001; //”1” – инвертированные значения из методички
break;
case 2:
PORTD = ~0b10100100;//”2”
break;
case 3:
PORTD = ~0b10110000;
break;
case 4:
PORTD = ~0b10011001;
break;
case 5:
PORTD = ~0b10010010;
break;
case 6:
PORTD = ~0b10000010;
break;
case 7:
PORTD = ~0b11111000;
break;
case 8:
PORTD = ~0b10000000;
break;
case 9:
PORTD = ~0b10010000;
break;
case 0:
PORTD = ~0b11000000;
break;
}
}
void interrupt timer0()
{j=i; k=0;
while(j>0) /* разделение числа i (2500…1500) на отдельные цифры в обратной последовательности*/
{
digit[k++] = j % 10;//заполнение массива с цифрами числа i
j = j / 10;
}
switch(TIM0_count/2) // проверка значения счетчика TIM0_count таймера
{
case 1: // вывод тысяч
PORTBbits.RB7 = 1;
segchar(digit[3]); /*из массива достаем цифру тысяч и отправляем ее не индикатор тысяч */
break;
case 2:// // вывод сотен
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
segchar(digit[2]);
break;
case 3: // вывод десятков
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 1;
segchar(digit[1]);
break;
case 4: // вывод единиц
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
segchar(digit[0]);
break;
case 5: // сброс счетчика TIM0_count таймера
PORTBbits.RB4 =0; // выкл последней цифры - единицы
TIM0_count=0;
upd++; счетчик для увеличения i - Частота смены 1 Гц.
break;
}
if (upd==20){ i=i-50;upd=0;if(i<1500)i=2500;}// i=2500…1500
TIM0_count++;
}
//--------------------------------------------------------------
void main(void) {
TRISD = 0x00;
PORTD = 0xFF;
TRISB = 0x00;
PORTB = 0x80;
OPTION_REG=0x00; // Предделитель частоты таймера = 2, f =2 МГц
INTCON=0xA0; // прерывание по таймеру вкл
TMR0=0;
while(1){}// тут пусто, все в прерывании
}