В программе реализован обычный 12-ти разрядный индикатор уровня. Разряд PB4 (вывод 3) микроконтроллера используется как вход АЦП (ADC2). Максимальное напряжение на входе ADC2 около 1.6 вольта. Состояние фьюзов - меняется, убирается делитель частоты на 8 (частота 1200000x8=9600000 Гц).
- Код: выделить все
//MCU = ATtiny13a
//F_CPU = 9600000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
typedef unsigned char uchar;
typedef unsigned int uint;
// Запуск таймера с предделителем на 64
#define ENABLE_TIMER \
TCCR0B &= 0b11111000;\
TCCR0B |= 0b00000011;
uint ledState = 0; // глобальная переменная, биты которой соответствуют состоянию светодиодов
// PROGMEM - хранить массивы в памяти программ, а не в оперативной.
// led_ddr - массив значений четырех битов регистра DDRB для включения нужного светодиода
// led_port - массив значений четырех битов регистра PORTB для включения нужного светодиода
// иднекс массива соответствует номеру светодиода.
const uchar led_ddr[12] PROGMEM = {
0b0011, 0b0011, 0b0110, 0b0110,
0b1100, 0b1100, 0b0101, 0b0101,
0b1001, 0b1001, 0b1010, 0b1010};
const uchar led_port[12] PROGMEM = {
0b0001, 0b0010, 0b0010, 0b0100,
0b0100, 0b1000, 0b0001, 0b0100,
0b0001, 0b1000, 0b0010, 0b1000};
// Функция включения одного из 12 светодиодов
// i - номер светодиода
static void led_on(uchar i);
static void led_scan(void); // Динамическая развертка
//Обработчик прерывания таймера по совпадению
ISR(TIM0_COMPA_vect, ISR_BLOCK) {
ledState = (1 << (ADCH * 13 / 83)) - 1; // установка уровня в зависимости от значения на АЦП
led_scan(); // динамическая развертка
}
int main(void) {
PORTB = 0b00000001;
DDRB = 0b00000011;
TCCR0A = 0b00000010; //Режим - сброс по совпадению (CTC)
TIMSK0 = (1 << OCIE0A); //Разрешение прерывания по совпадению с OCR0A
OCR0A = 64;
ENABLE_TIMER;
ADMUX = 0b00100010;
ADCSRA = 0b11100111;
DIDR0 = 0b00010000;
sei(); // Глобальное разрешение прерываний
for(;;) {} // Бесконечный цикл
}
// Функция включения одного из 12 светодиодов
// i - номер светодиода
void led_on(uchar i){
DDRB &= 0b11110000; // Обнуление ножек к которым подключены светодиоды
PORTB &= 0b11110000;
DDRB |= pgm_read_byte(led_ddr + i); // установка значений из массива в регистры для включения нужного светодиода
PORTB |= pgm_read_byte(led_port + i);
}
/* Макрос pgm_read_byte(array + i)
* Возвращает байт из массива array под индексом i.
* Используется вместо array[i],
* так как массивы led_ddr и led_port сохранены не в оперативной памяти,
* а в памяти программ.
*/
// Функция динамической развертки
void led_scan(void) {
static uchar i = 0;
static uint shiftedLedState = 0;
if((shiftedLedState & 0x01) == 1) // Если i-ый бит равен 1, то зажечь i-ый светодиод, иначе отключить все светодиоды
led_on(i);
else
PORTB &= 0xF0;
i++;
shiftedLedState >>= 1;
if(i == sizeof(led_ddr)) { // Если все биты пройдены, то начать заново
i = 0;
shiftedLedState = ledState;
}
}
Задание :
По коду программы максимальное значение напряжения от источника сигнала около 1.6 вольта. Измените и примените вид выражения “ledState = (1 << (ADCH * 13 / 83)) - 1” таким, чтобы при изменении напряжения от 0 до 5 вольт на входе АЦП последовательно включались все двенадцать светодиодов.