Начал осваивать AVR, есть Arduino на Atmega328P, делаю задание по подключению двухразрядного LED-индикатора, в перспективе - термометр. Набросал код и не пойму, в Протеусе в обоих разрядах индикатора одинаковые цифры. Это ошибка в коде или надо как-то настроить Протеус?
Сильно не пинайте, я только учусь.
Вот схема:
и код, присутствуют некоторые Ардуино-специфичные функции:
Спойлер
Код: Выделить всё
/*
* Соответствие отображаемого знака данным порта
общий анод
_____
| двоичный вид по сегментам | | |
Цифра|dp | G | F | E | D | C | B | A | Десятичный | Шестнадцатиричный |
-----|---|---|---|---|---|---|---|---|----------|----------|
0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 192 | 0xC0 |
1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 249 | 0xF9 |
2 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 164 | 0xA4 |
3 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 176 | 0xB0 |
4 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 153 | 0x99 |
5 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 146 | 0x92 |
6 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 130 | 0x82 |
7 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 248 | 0xF8 |
8 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 128 | 0x80 |
9 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 144 | 0x90 |
dp | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 127 | 0x7F |
-----*---*---*---*---*---*---*---*---*----------*----------+
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <OneWire.h>
// пример использования библиотеки OneWire DS18S20, DS18B20, DS1822
#define DIG_BASE 10 // основание системы счисления для перевода
#define MAX_SIZE 2 // максимальное число выводимых символов
#define SPACE_CHAR 0xFF // символ "пустого" места
#define NEG_CHAR 0xBF // символ "минус"
// Определения, к каким выводам подключены сегменты индикатора и разряды
#define SEG_A 6
#define SEG_B 7
#define SEG_C 8
#define SEG_D 9
#define SEG_E 10
#define SEG_F 11
#define SEG_G 12
#define RAZR_1 4
#define RAZR_2 5
// массив символов, соответствующих ЦИФРАМ выбранной системы счисления
unsigned char SYMBOLS[DIG_BASE] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
volatile unsigned char out[MAX_SIZE]; // выходной массив символов (экранная область)
unsigned char segm[7] = {6,7,8,9,10,11,12}; // массив с номерами выводов, к которым подключены сегменты (A-G)
unsigned char razr[MAX_SIZE] = {4,5}; // массив с номерами выводов управления разрядами
OneWire ds(13); // на пине D13 (нужен подтягивающий резистор 4,7 кОм)
void convert(unsigned int NUM) {
int i, m, sign = 0;
if(NUM <0) {
// если число отрицательное
sign = 1; // установим признак наличия знака
NUM *= -1; // а само число возьмем по модулю
}
// выводим уже положительное число
i=MAX_SIZE-1;
do {
// цикл заполнения выходного массива СПРАВА НАЛЕВО
m = NUM % DIG_BASE; // находим остаток от деления числа на основание
if((NUM==0)&&(i!=(MAX_SIZE-1)))
break; // закончим цикл вывода числа
else
out[i] = SYMBOLS[m]; // иначе выводим символ нужной ЦИФРЫ
NUM /= DIG_BASE; // уменьшаем число в DIG_BASE раз
} while (--i >= 0);
// число выведено, проверяем свободное место и выводим при необходимости знак
if (i < 0) return; // места не хватает - выход
if (sign) out[i--] = NEG_CHAR; // выводим знак, если нужно
for(; i>=0;i--) out[i] = SPACE_CHAR; // очищаем незначащие позиции
}
void setup(void) {
// Функция инициализации МК
OCR0A = 0x0F; // До какого значения считать
TIMSK0 |= _BV(OCIE0A); // Прерывание по совпадению таймера (устанавливает в "1" бит, другой вариант записи - TIMSK0 |= 1 << OCIE0A)
// устанавливаем режимы для пинов
pinMode(SEG_A, OUTPUT);
pinMode(SEG_B, OUTPUT);
pinMode(SEG_C, OUTPUT);
pinMode(SEG_D, OUTPUT);
pinMode(SEG_E, OUTPUT);
pinMode(SEG_F, OUTPUT);
pinMode(SEG_G, OUTPUT);
pinMode(RAZR_1, OUTPUT);
pinMode(RAZR_2, OUTPUT);
Serial.begin(9600); // инициализация консоли
interrupts(); // разрешаем прерывания (аналог - sei();)
}
void loop(void) {
// Основная функция программы
unsigned char disp = 0;
// Тестовый вывод цифр на индикатор
while (1) {
disp++;
Serial.print(" Data to display = ");
Serial.print(disp);
Serial.println();
convert(disp);
if (disp >= 255) disp = 0;
delay(500);
}
}
SIGNAL (TIMER0_COMPA_vect) {
// Обработчик прерывания таймера
static unsigned char pos = 0, i;
// digitalWrite(RAZR_1,HIGH); // Выключаем оба знакоместа
// digitalWrite(RAZR_2,HIGH);
PORTD |= 3<<4; // Устанавливаем в 1 разряды порта PD4-PD5, выключаем знакоместа
for (i = 0; i <= 50; i++) {} // Пустой цикл для задержки выключения транзистора разряда
PORTD |= 3<<6; // По идее, устанавливаем в 1 биты PD6-PD7 (сегменты A и B)
PORTB |= 0x1F; // Устанавливаем в 1 разряды порта PB0-PB4 (сегменты C-G), это гасит сегменты
for (i = 0; i <= 50; i++) {} // Пустой цикл для задержки
i = out[pos] | 0xFC; // Выделяем из байта "видеопамяти" два младших бита, помещаем их во временную переменную
PORTD &= i << 6; // Сдвигаем эти два бита на 6 позиций влево, перемещая их в позиции 6 и 7 и зажигаем сегменты (устанавливая 0)
PORTB &= out[pos] >> 2; // Берем остальные биты (сегменты C-G) и сдвигаем их в позиции PB0-PB4
if(pos == 0) digitalWrite(RAZR_1,LOW); else digitalWrite(RAZR_2,LOW); // Включаем разряд
for (i = 0; i <= 50; i++) {}
// Если pos достиг максимального значения - обнуляем его, иначе - инкрементируем
(pos == MAX_SIZE-1) ? pos = 0 : pos++;
}