#include <mega8.h> #include <delay.h> #include <stdio.h> #asm .equ __lcd_port=0x12 ;PORTD #endasm #include <lcd.h> #define ADC_VREF_TYPE 0x40// Опорна напруга АЦП з ножки AVCC //TCCR1B #define CS0 0 #define CS1 1 #define CS2 2 // Read the AD conversion result unsigned int read_adc(unsigned char adc_input) { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); // Delay needed for the stabilization of the ADC input voltage delay_us(10); // Start the AD conversion ADCSRA|=0x40; // Wait for the AD conversion to complete while ((ADCSRA & 0x10)==0); ADCSRA|=0x10; return ADCW; } // global variables unsigned int adc_code,old_code=1, pwm; unsigned char string[10];//масив знаків для виводу на дисплей void main(void) { // ADC initialization // ADC Clock frequency: 250,000 kHz // ADC Voltage Reference: AVCC pin ADMUX=ADC_VREF_TYPE & 0xff; ADCSRA=0x85; DDRB=0xFF;//Порт Б на виход //Fast PWM 8-bit //OC1A встановлюється в 1 при свівпаданні (COM1A1=1, COM1A0=1) //OC1B скидається в 0 при свівпаданні (COM1B1=1, COM1B0=0) TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<WGM10); TCCR1B=(1<<CS0)|(1<<WGM12); // LCD module initialization lcd_init(16);// Дисплей на 16 символів lcd_clear();// Очищаємо дисплей lcd_gotoxy(0,0);// Ставим курсор на 0 знак та 0 стрічку lcd_putsf(" LCD PWM Control ");//Вивод повідомлення на нульову стрічку (першу) lcd_gotoxy(0,1);// Ставим курсор на 0 знак та 0 стрічку lcd_putsf("PWN 0-100%: %");//Вивод повідомлення на нульову стрічку (першу) delay_ms(100); while (1) { adc_code=read_adc(0)/4;// Зчитуємо результат АЦП if(adc_code!=old_code) //Якщо значення з АЦП змінилось { old_code=adc_code; pwm=(adc_code*100)/255;//Перетворення коду 0-1023 в 0-100% для виведення на lcd sprintf(string, "%d",pwm);//формуємо стрінг із змінної "pwm" //типу int в десятковому вигляді //заносим значення в регістри порівняння OCR1A=adc_code; OCR1B=adc_code; lcd_gotoxy(12,1); lcd_puts(string);// Виводимо значення змінної "pwm" } delay_ms(100); }; }
Електроніка та програмування
пʼятниця, 16 січня 2015 р.
Апаратний ШІМ мікроконтролера Atmega8 + PWM+LCD
Аналого-цифровий перетворювач, вольтметр на базі мікроконтролера ADC Atmega8 CodeVision AVR
#include <mega8.h> #include <delay.h> #include <stdio.h> #asm .equ __lcd_port=0x18 ;PORTB #endasm #include <lcd.h> #define ADC_VREF_TYPE 0x40// Опорна напруга АЦП з ножки AVCC // Read the AD conversion result unsigned int read_adc(unsigned char adc_input) { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); // Delay needed for the stabilization of the ADC input voltage delay_us(10); // Start the AD conversion ADCSRA|=0x40; // Wait for the AD conversion to complete while ((ADCSRA & 0x10)==0); ADCSRA|=0x10; return ADCW; } // global variables float adc_code, voltage; unsigned char string[4];//масив знаків для виводу на дисплей void main(void) { // ADC initialization // ADC Clock frequency: 250,000 kHz // ADC Voltage Reference: AVCC pin ADMUX=ADC_VREF_TYPE & 0xff; ADCSRA=0x85; // LCD module initialization lcd_init(16);// Дисплей на 16 символів lcd_clear();// Очищаємо дисплей lcd_gotoxy(0,0);// Ставим курсор на 0 знак та 0 стрічку lcd_putsf(" LCD voltmeter ");//Вивод повідомлення на нульову стрічку (першу) lcd_gotoxy(0,1);// Ставим курсор на 0 знак та 0 стрічку lcd_putsf(" Voltage: V ");//Вивод повідомлення на нульову стрічку (першу) delay_ms(100); while (1) { adc_code=read_adc(0);// Зчитуємо результат АЦП voltage=(adc_code*5)/1024;// Перетворення в напругу sprintf(string, "%.2f",voltage);//формуємо стрінг із змінної "voltage" //типу float з двома знаками після коми lcd_gotoxy(9,1); lcd_puts(string);// Виводимо значення напруги delay_ms(100); }; }
четвер, 15 січня 2015 р.
Робота з рідиннокристалічним дисплеєм Atmega8 + LCD + CodeVision
#include <mega8.h> #include <delay.h> #include <stdio.h> // Інціалізація підключення дисплея #asm .equ __lcd_port=0x18 ; PORTB #endasm #include <lcd.h> unsigned int temp = 32000;//змінна яку будемо виводити unsigned char string[20];//масив знаків для виводу на дисплей bit p=0; //Для зміни рядків void main(void) { lcd_init(16);//Ініціалізуємо дисплей lcd_clear();// Очищаємо дисплей lcd_gotoxy(0,0);// Ставим курсор на 0 знак та 0 стрічку lcd_putsf("LCD test");//Вивод повідомлення на нульову стрічку (першу) lcd_gotoxy(0,1); //Перехід курсора на першу стрічку lcd_putsf("CHISLO...");//Вивод інформаційного повідомлення на першу стрічку(другу) lcd_gotoxy(10,1); // Вивід символів... lcd_putchar('A'); lcd_gotoxy(12,1); lcd_putchar(0x41); delay_ms(3000); //Висить заставка lcd_clear(); // Очищаємо дисплей while (1) { sprintf(string, "temp=%5d\n", temp);//формуємо стрінг із змінної lcd_gotoxy(0,p++); //%5 - 5 знаків d - в десяткове знакове число //\n - з переходом на наступну стрічку lcd_puts(string); delay_ms(1000); temp++; // Нарощуємо змінну для виведення } }
Матрична клавіатура 3х4 на Atmega8 CodeVision AVR
#define COLUMN 3 // Кількість колонок #define ROW 4 // Кількість рядків #include <mega8.h> #include <delay.h> unsigned char button;//Номер кнопки (позиційний) //Значення що подаються для сканування рядків unsigned char key_tab[ROW] ={0b11111110, 0b11111101, 0b11111011, 0b11110111}; // Функція опитування клавіатури unsigned char scan_key(void) { unsigned char key_value = 0; unsigned char i; for(i = 0;i < ROW;i++)//Виводимо почерзі 0 в рядки { PORTB = key_tab[i]; delay_us(100); switch (PINB & 0xF0)// Зчитуємо значення з порта В { //та обчислюємо номер кнопки case 0b11100000: key_value = 1 + i * COLUMN; return (key_value); case 0b11010000: key_value = 2 + i * COLUMN; return (key_value); case 0b10110000: key_value = 3 + i * COLUMN; return (key_value); break; } } } void main(void) { // Масив цифр для індикатора unsigned char num[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; DDRB |= (1 << 3)|(1 << 2)|(1 << 1)|(1 << 0); // Порт вихода DDRB &= ~(1 << 7)|(1 << 6)|(1 << 5)|(1 << 4); // Порт входа PORTB = 0xF0; // Встановлюємо лог. 1 в порт входа DDRD = 0xFF; // Виход на індикатор PORTD = 0x00; delay_us(100); while(1) { for(button=1;button<10;button++) { if(scan_key()==button) // Виводим значення натисненої кнопки на індикатор PORTD = num[button]; } if(scan_key()==11) // 0 на 11 кнопці PORTD = num[0]; } }
середа, 14 січня 2015 р.
Семисегментний дисплей на MAX7219 Atmega8 CodeVision AVR
//**************************************************** #include <mega8.h> #include <delay.h> //---------------------------------------------------- // Задамо глобальні контанти та змінні #define PIN_SCK PORTB5 // Тактовий вихід Master_SPI #define PIN_MOSI PORTB3 // Вихід даних Master_SPI #define PIN_SS PORTB2 // Вибір кристала (завантаження на вихід) #define PIN_SS1 PORTB1 // Вибір кристала для паралельного запису //(можна використовувати для збільшення швидкодії) #define ON 1 #define OFF 0 #define cs_lo PORTB |= (1<<PIN_SS) // 1 на SS дані можуть записуватись в регістр зсуву (16-розрядн.) #define cs_hi PORTB &= ~(1<<PIN_SS)// 0 на SS активний вибір кристала //(завантаження записаних даних на порт) #define cs1_lo PORTB |= (1<<PIN_SS1) //те саме для паралельного запису #define cs1_hi PORTB &= ~(1<<PIN_SS1) //------------------------------------------------------ //Адреси регістрів настройки МАХ7219 //------------------------------------------------------ #define MAX7219_MODE_DECODE 0x09 // Декадний режим #define MAX7219_MODE_INTENSITY 0x0A // Яскравість #define MAX7219_MODE_SCAN_LIMIT 0x0B// Розряднісь дисплея #define MAX7219_MODE_POWER 0x0C // Вимкнення живлення #define MAX7219_MODE_TEST 0x0F // Тестовий режим #define MAX7219_MODE_NOOP 0x00 // Пуста операція //Адреси регістрів сегментів const unsigned char MAX7219_DIGIT[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; #define MAX7219_CHAR_BLANK 0xF // пустота #define MAX7219_CHAR_NEGATIVE 0xA // мінус "-" #define BYTE_SYMBOL 0x08 //Максимальна кількість символів unsigned char active_digit = 8;//к-ть активних розрядів дисплея unsigned char number_of_displays=2;//к-ть активних дисплеїв unsigned char i,j;// лічильники //------------------------------------------------------------------------- //Фукнція запису по SPI (апаратний) //------------------------------------------------------------------------- void spiSendByte (char databyte) { SPDR = databyte; //записуємо переданий байт в регістр SPI while (!(SPSR & (1 << SPIF)));//Якщо все передали флаг встановлюється і ми виходими з функції } //----------------------------------------------------------------------------------------- // Функція запису в MAX7219 (пакет 16-біт!!) //----------------------------------------------------------------------------------------- void MAX7219_writeData(char data_register, char data,unsigned char chip) { unsigned short k; cs_hi; //Slave_SPI активний може приймати дані spiSendByte(data_register);//старші біти передаємо першими spiSendByte(data);// їх потіснять на місця біти байта даних for(k=0;k<2*chip;k++)// якщо кількість каскадованих чіпів більша 1(лічба з 0) {// то потрібно подати пару пустих байтів після посилки //вони продавлять дані на наступний чіп spiSendByte(MAX7219_MODE_NOOP); // пустота операція }// Нічого не робить але зміщає все на один байт //не дивуйтесь, спочатку пишеться адреса а потім дані які є адресою? але це вже не грає ніякої ролі бо операція пуста!! // головне зміщення на 2 байта а все інше не міняється! cs_lo; // Закриваємо Slave_SPI } /*Функція очистки дисплея може колись знадобиться... void clear_display() { unsigned char i,j; for(j=0;j<3;j++) { for(i=1;i<=active_digit;i++) { MAX7219_writeData(i, MAX7219_CHAR_BLANK,j); } } } */ //------------------------------------------------------------------------------------------ //Функція виводу даних на дисплей через MAX7219 //------------------------------------------------------------------------------------------ void display(unsigned char data_disp) { for(j=0;j<BYTE_SYMBOL;j++){ MAX7219_writeData(MAX7219_DIGIT[j],data_disp,0); MAX7219_writeData(MAX7219_DIGIT[j],data_disp+1,1); } } //-------------------------------------------------------------------------------------------- void main(void) { unsigned int j; DDRB |= (1 << PIN_SCK) | (1 << PIN_MOSI) | (1 << PIN_SS)| (1 << PIN_SS1);//виходи для SPI SPCR |= (1 << SPE) | (1 << MSTR)| (1<<SPR1);// Вмикаємо SPI, Режим мастер, старшим бітом вперед /Швидкість f/64 for(j=0;j<number_of_displays;j++)// налаштування кожного чіпа МАХ7219 { MAX7219_writeData(MAX7219_MODE_DECODE,0xFF,j); // декадний режим включено MAX7219_writeData(MAX7219_MODE_SCAN_LIMIT,active_digit-1,j);// Всі сегменти скануються 0-7 MAX7219_writeData(MAX7219_MODE_INTENSITY, 8,j); // яскравість на половину 17/34 MAX7219_writeData(MAX7219_MODE_POWER, ON,j);// вмикаємо всі табла } while(1) { display(i);// Виводимо змінну яку наращуємо кожну секунду delay_ms(1000); i++; if(i==10) i=0; } }
вівторок, 13 січня 2015 р.
Годинник на Atmega8 + DS1302
Схема годинника на DS1302 в Proteus |
#asm // Асемблерна вставка ініціалізації підключення мікросхеми DS1302 до Atmega8 .equ __DS1302_port=0x15;//Подключаем DS1302 к PORTС(0x15-адреса регістра порта) .equ __DS1302_io=2 ;//Другий пін для io .equ __DS1302_sclk=1 ;//Перший пін для sclk .equ __DS1302_rst=0 ;//Нульовий пін для rst #endasm
#include <bcd.h> #include <mega8.h> #include <delay.h> #include <DS1302.h> #define DIGITS 6 // Кількість розрядів індикатора unsigned char chislo[DIGITS]; //масив чисел, що відповідають кожному розряду unsigned char numder[]= //масив, в якому індексу будут відповідати біти на порту D для кожної цифри { 0b00111111, //цифра 0 0b00000110, //цифра 1 0b01011011, //цифра 2 0b01001111, //цифра 3 0b01100110, //цифра 4 0b01101101, //цифра 5 0b01111101, //цифра 6 0b00000111, //цифра 7 0b01111111, //цифра 8 0b01101111, //цифра 9 0b00000000, //пусто }; unsigned char hour_1, minute_1;//години та хвилини для наведення unsigned char second, minute, hour, date, month, year;// змінні часу та дати bit Button_1_state, Button_2_state; unsigned short i=0; // змінна, що визначає номер розряду який виводиться unsigned short k, dp; // змінні для крапки //***************************************************************************** // преривання по переповненню timer0 interrupt [TIM0_OVF] void timer0_ovf_isr(void) { PORTB=0x3f; // погасимо індикатор if (i==2||i==4) dp=k;//виводимо крапку на 2 та 4 індикатор else dp=0; PORTD=((numder[ chislo[i]])|dp); // виведем поточне число PORTB=~(1<<i); // вмикаємо відповідний розряд індикатора if (i++>DIGITS) i=0; // якшо не дійшли до старшого розряду готуєм виведення наступного } // якшо дійшли до старшого розряду готуєм виведення нульового //***************************************************************************** void out_1(unsigned short num)//виведення першої пари знаків (для секунд) { chislo[0]=num%10; //одиниці секунд chislo[1]=num/10; // десятки k=(~k)&0b10000000;// крапка засвічується та гасне кожну секунду } void out_2(unsigned short num)//виведення другої пари знаків (для хвилин) { chislo[2]=num%10; //одиниці хвилин chislo[3]=num/10; // десятки } void out_3(unsigned short num)//виведення третьої пари знаків (для годин) { chislo[4]=num%10; //одиниці годин chislo[5]=num/10; // десятки } //**************************************************************************** void main(void) { //Порт В PORTB=0x00; DDRB=0b00111111; //PB0-3 виходи (розряди) //Порт С PORTC=0b00111111; //включимо підтягуючі резистори на PС0-5 DDRC=0b00000000; //PС0-3 входи (кнопки + DS1302) //Порт Д PORTD=0b0000000; DDRD=0b11111111; //PD0-PD6 виходи (сегменти) TCCR0=0x03; //встановлюємо подільник таймера 64 rtc_init(0,0,0);//Ініціалізація DS1302 // кожне перерив приблизно 2 мс rtc_set_date(13,01,15);//встановлюємо дату 13.01.15 TIMSK=0x01;// переривання по переповненню таймера 0 #asm("sei")// глобальний дозвіл перерывання
//*************************************************************************** while (1) //основний цикл { rtc_get_time(&hour,&minute,&second);//зчитуємо години, хвилини, секунди // у відповідні змінні out_1(second); //виводимо на індикатор секунди out_2(minute); //хвилини out_3(hour); // години while (PINC.3==0){ //Поки натиснена кнопка збільшення хвилин k=0x80;// крапки засвічуються minute++; // збільшуємо хвилини кожні 300мс в діапазоні 0-60 if(minute==60)minute=0; minute_1 = bin2bcd(minute);// перетворюємо двійкове число в двійково-десяткове out_2(minute);//виводимо на індикатор хвилини які наводимо delay_ms(300); Button_1_state = 1; } while (PINC.4==0){ //Поки натиснена кнопка збільшення годин k=0x80;// крапки засвічуються hour++; // збільшуємо години кожні 300мс в діапазоні 0-24 if(hour==24)hour=0; hour_1 = bin2bcd(hour); out_3(hour); //виводимо на індикатор delay_ms(300); Button_2_state = 1; } delay_ms(500); if (Button_1_state && PINC.3){// Якщо кнопка наведення хвилин була натиснена і її тільки що відпустили ds1302_write(0b10000010, minute_1);//Записуємо нове виставлене значення хвилин в 1302 ds1302_write(0b10000000, 0);//Скидаємо секунди в 0 в 1302 Button_1_state = 0;// скидаємо фіксатор } if (Button_2_state && PINC.4){// Якщо кнопка наведення годин була натиснена і її тільки що відпустили ds1302_write(0b10000100, hour_1);//Записуємо нове виставлене значення годин в 1302 Button_2_state = 0; } while (PINC.5==0){ // Поки кнопка дати натиснена k=0;// розділові крапки засвічуються rtc_get_date(&date, &month, &year); // зчитується дата out_1(year); //виводимо на індикатор рік out_2(month); //місяць out_3(date); //число delay_ms(500); } } }
Sourse_file (Proteus in folder EXE)
понеділок, 12 січня 2015 р.
Годинник на індикаторі 7 segment AVR
Годинниковий кварцевий резонатор |
#include <mega8.h> #include <delay.h> #define DIGITS 6 // Кількість розрядів індикатора unsigned char chislo[DIGITS]; //масив чисел, що відповідають кожному розряду unsigned char numder[]= //масив, в якому індексу будут відповідати біти на порту D для кожної цифри { 0b00111111, //цифра 0 0b00000110, //цифра 1 0b01011011, //цифра 2 0b01001111, //цифра 3 0b01100110, //цифра 4 0b01101101, //цифра 5 0b01111101, //цифра 6 0b00000111, //цифра 7 0b01111111, //цифра 8 0b01101111, //цифра 9 0b00000000, //пусто }; // змінні, години:хвилини:секунди які виводиться на дисплей unsigned short old_sek=1, sek=0, old_min=1, min=0, old_chas=5, chas=0; unsigned short i=0; // змінна, що визначає номер розряду який виводиться unsigned short k, dp; // змінні для крапки // преривання по переповненню timer0 interrupt [TIM0_OVF] void timer0_ovf_isr(void) { PORTB=0x3f; // погасимо індикатор if (i==2||i==4) dp=k;//виводимо крапку на 2 та 4 індикатор else dp=0; PORTD=((numder[ chislo[i]])|dp); // виведем поточне число PORTB=~(1<<i); // вмикаємо відповідний розряд індикатора if (i++>DIGITS) i=0; // якшо не дійшли до старшого розряду готуєм виведення наступного } // якшо дійшли до старшого розряду готуєм виведення нульового // Переривання по співпаданню таймера 2 (відбувається кожну секунду) ) interrupt [TIM2_COMP] void timer2_comp_isr(void){ sek++;// нарощення секунд if(sek==60){ sek=0; min++;// нарощення хвилин } if(min==60){ min=0; chas++;// нарощення годин } if(chas==24){ chas=0; } } void out_1(unsigned short num)//виведення першої пари знаків (для секунд) { chislo[0]=num%10; //одиниці секунд chislo[1]=num/10; // десятки k=(~k)&0b10000000;// крапка засвічується та гасне кожну секунду } void out_2(unsigned short num)//виведення другої пари знаків (для хвилин) { chislo[2]=num%10; //одиниці хвилин chislo[3]=num/10; // десятки } void out_3(unsigned short num)//виведення третьої пари знаків (для годин) { chislo[4]=num%10; //одиниці годин chislo[5]=num/10; // десятки } void main(void) { //Порт В PORTB=0x00; DDRB=0b00111111; //PB0-3 виходи (розряди) //Порт С PORTC=0x0f; //включимо підтягуючі резистори на PС0-3 DDRC=0b00000000; //PС0-3 входи (розряди) //Порт Д PORTD=0b0000000; DDRD=0b11111111; //PD0-PD6 виходи (сегменти) TCCR0=0x03; //встановлюємо подільник таймера 64 // кожне перерив приблизно 2 мс //********* Налаштування таймера 2*************************** ASSR=0b00001000;// включили асинхронний режим TCNT2=0x00; //занулення регістра лічильника OCR2=127;// число з яким порівнюється вміст лічильника TCCR2=0b00000110;//подільник частоти з коеф. 256 delay_ms(100);// затримка для введення асинхронного лічильника TCCR2 |=(1<<WGM21);//обнулення лічильника при співпаданні //************************************************************ TIMSK=0x81;//прерывания по переполнению таймера 0 та співпадання таймера 2 #asm("sei")// глобальний дозвіл перерывання while (1) //основний цикл { if(old_sek!=sek) { //Якщо секунди змінились out_1(sek); //виводимо на індикатор old_sek=sek; } if(old_min!=min) { //Якщо хвилини змінились out_2(min); //виводимо на індикатор old_min=min; } if(old_chas!=chas) {//Якщо години змінились out_3(chas); //виводимо на індикатор old_chas=chas; } if (PINC.0==0){ //Якщо натиснена кнопка збільшення хвилин min++; // збільшуємо хвилини кожні 200мс в діапазоні 0-60 if(min==60)min=0; delay_ms(200); } if (PINC.1==0){ //Якщо натиснена кнопка збільшення годин chas++; // збільшуємо години кожні 200мс в діапазоні 0-24 if(chas==24)chas=0; delay_ms(200); } } }
Модель годинника в Proteus |
Підписатися на:
Дописи
(
Atom
)