Примеры CodeVisionAVR - Генератор импульсов & ЖКИ

Автор: Internet. Опубліковано в Початківцям з CV AVR

Зміст статті

 
Генератор  источник импульсов.Выходная частота, снимаемая с выхода ШИМ (вывод 15 МК), задается энкодером с кнопкой и показывается на экране ЖКИ
Тактовая частота МК стабилизируется кварцем 8МГц
При нажатии и удержании кнопки энкодера 0.5с меняется возможность установки частоты при подаче питания генератор выключен, импульсы на выходе появляются при повороте ручки энкодера, частоту можно менять на 1Гц; после первого нажатия кнопки энкодера частоту можно задавать десятками герц, после второго - сотнями и после третьего нажатия кнопки,
 
частота меняется тысячами герц (до 30кГц); затем все повторяется.
 
О точности.
Значения выходной частоты проверялись осциллографом. На малых частотах, примерно до 200Гц, значения совпадают с измеренными на осциллографе, затем чем больше частота, тем больше погрешность (это получается из-за нецелых чисел, записываемых в регистр сравнения). Точность можно повысить, если в регистр сравнения заносить константы из массива (мне высокие частоты не нужны были, да и просто лень считать и заносить числа в массив))), На высоких частотах, чтобы повысить точность, нужно брать другую частоту таймера.
Разъем J1 для внутрисхемного программирования МК.
Code
/*****************************************************
Project : Pulse Generator
Version : 1.0
Date : 19.09.2010
Author : Serega (Deneb-80)
Comments: Модернизация c2.at.ua.

Chip type : ATmega8
Program type : Application
Clock frequency : 8,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>
#asm
.equ __lcd_port=0x12 ;PORTD
#endasm
#include <lcd.h>
#include <stdio.h>
unsigned char lcd_buffer[33]; // массив с данными для экрана
unsigned char ENC_COUNT=0; // счетчик для кнопки энкодера
unsigned int EncData=0; // 0...65535
unsigned int F0=0;
float temp;
float div1;

#define Fclk 8000000.000

#define div 64.000 // предделитель таймера T1. Если предделитель равен 64,
#define MIN_VALUE 0 // то максимальная частота будет 30кГц, т.к. после будут
#define MAX_VALUE 30000 // уже отрицательные значения в регистре OCR1A


void Encquest(void)
{

switch (ENC_COUNT)
{
case 0:{if ((PINC.4==0)&(PINC.5==1)&(EncData<MAX_VALUE))
{
delay_ms(250);
EncData += 1;
};
if ((PINC.4==1)&(PINC.5==0)&(EncData>MIN_VALUE))
{
delay_ms(250);
EncData -= 1;
};
break;
}
case 1:{
if ((PINC.4==0)&(PINC.5==1)&(EncData<=(MAX_VALUE-10)))
{
delay_ms(250);
EncData += 10;
};
if ((PINC.4==1)&(PINC.5==0)&(EncData>=(MIN_VALUE+10)))
{
delay_ms(250);
EncData -= 10;
};
break;
}
case 2:{
if ((PINC.4==0)&(PINC.5==1)&(EncData<=(MAX_VALUE-100)))
{
delay_ms(250);
EncData += 100;
};
if ((PINC.4==1)&(PINC.5==0)&(EncData>=(MIN_VALUE+100)))
{
delay_ms(250);
EncData -= 100;
};
break;
}
case 3:{
if ((PINC.4==0)&(PINC.5==1)&(EncData<=(MAX_VALUE-1000)))
{
delay_ms(250);
EncData += 1000;
};
if ((PINC.4==1)&(PINC.5==0)&(EncData>=(MIN_VALUE+1000)))
{
delay_ms(250);
EncData -= 1000;
};
break;
}

} // switch

} // подпрограмма опроса


// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
Encquest();

}

void main(void)
{
// Declare your local variables here
PORTB=0b00000000;
DDRB=0b00000000;
PORTC=0b10111000; // «WzAVR «Port C initialization
DDRC=0b00000000;
PORTD=0b00000000; // «WzAVR «Port D initialization
DDRD=0b00000000;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
TCCR0=0x03;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: CTC top=OCR1A
// OC1A output: Toggle
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x40;
TCCR1B=0x0B;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

/******************* Инициализация ЖКИ ***********************/
lcd_init(16);
#asm("sei")
lcd_clear(); // чистим дисплей перед выводом
lcd_putsf("Generator vkl."); // записываем в массив для экрана
lcd_puts(lcd_buffer); // выводим массив на LCD
lcd_gotoxy(0,1); // переходим на вторую строку
lcd_putsf("ShIM + chastota ");
delay_ms(2000);
lcd_clear();

while (1)
{
if (PINC.3==0 ) { //вход в меню настроек
while(PINC.3==0); //
lcd_clear();
ENC_COUNT++; //Установка шага частоты
delay_ms(15);
};
if (ENC_COUNT>3) ENC_COUNT = 0;


if (EncData>0)
{
DDRB=0x02; // делаем PB1 выходом
F0 = EncData;
div1 = (float)(2*div*F0);
temp = (float)((Fclk/div1)-1); // деление на 2 - это сдвиг вправо на одно значение
OCR1A = temp;
}
if (F0!=EncData)
{
F0 = EncData;
}

if (F0==0)
{
DDRB=0x00; //отключаем частотный выход
lcd_gotoxy(0,0);
sprintf(lcd_buffer, "freq.= 0Hz ");
lcd_puts(lcd_buffer); // частота 0.0Hz
}


if ((F0>0)&(F0<1000))
{
lcd_gotoxy(0,0);
sprintf(lcd_buffer, "freq.= %uHz ", F0);
lcd_puts(lcd_buffer); // выводим массив на LCD

}
else
{

if ((F0>0)&(F0%1000)<10)
{
lcd_gotoxy(0,0);
sprintf(lcd_buffer,"freq.=%u.00%ukHz ", F0/1000, F0%1000);
lcd_puts(lcd_buffer);
}

if ((F0>0)&((F0%1000)>=10)&((F0%1000)<100))
{
lcd_gotoxy(0,0);
sprintf(lcd_buffer,"freq.=%u.0%ukHz ", F0/1000, F0%1000);
lcd_puts(lcd_buffer);
}

if ((F0>0)&(F0%1000)>=100)
{
lcd_gotoxy(0,0);
sprintf(lcd_buffer,"freq.=%u.%ukHz ", F0/1000, F0%1000);
lcd_puts(lcd_buffer);
}

};


switch (ENC_COUNT)
{
case 0:{
lcd_gotoxy(0,1);
sprintf(lcd_buffer, "step set.*1Hz ");
lcd_puts(lcd_buffer);

break;
}
case 1:{
lcd_gotoxy(0,1);
sprintf(lcd_buffer, "step set.*10Hz ");
lcd_puts(lcd_buffer);
break;
}
case 2:{
lcd_gotoxy(0,1);
sprintf(lcd_buffer, "step set.*100Hz ");
lcd_puts(lcd_buffer);
break;
}
case 3:{
lcd_gotoxy(0,1);
sprintf(lcd_buffer, "step set.*1000Hz");
lcd_puts(lcd_buffer);
break;
}

} // switch

};
}

Скачать исходный проект с proteus.