Чт апр 18, 2019 23:08:12
Пт апр 19, 2019 04:32:49
Сб апр 27, 2019 10:04:44
/*
* GccApplication1.c
* ATMEGA48
#define F_CPU 8000000UL // 8 MHz
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRB = 0xFF; // все выводы порта B сконфигурировать как выходы
DDRD = 0xFF; // все выводы порта D сконфигурировать как выходы
DDRC = 0x00; // все выводы порта C сконфигурировать как входы
while (1)
if ((PINC &(1<<PC1))==1) // Если нажата кнопка
{
while((PINC &(1<<PC1))==1){} // Ждем отпускания кнопки
PORTB =0xFF; PORTD =0xFF; _delay_ms(500); // Включение группы портов B и D
}
}
Сб апр 27, 2019 11:07:33
Неверное условие. PINC & (1<<PC1) никогда не будет равно 1. Либо 0, либо 2Prod писал(а):if ((PINC &(1<<PC1))==1) // Если нажата кнопка
if ((PINC & (1<<PC1)) == (1<<PC1))
if ((PINC & (1<<PC1))
Сб апр 27, 2019 11:52:14
Сб апр 27, 2019 12:01:50
Вс апр 28, 2019 15:23:38
Ср май 01, 2019 00:39:17
if ((data & MASK) != 0)
if ((data & MASK) == BITS)
Вт июн 04, 2019 19:19:21
/*
МК ATMEGA8
Частота МК = 8 МГц
Fuse High Byte
Fuse Low Byte
*/
//Подключенные файлы
#include <avr/io.h> // Стандартные функции ввода/вывода для МК
#include <avr/interrupt.h> // Стандартные функции работы с прерываниями
//Подстановки
//Прототипы функций
//Процедура инициализации входов/выходов
void init_IO(void);
//Процедура инициализации ТС1
void init_TC1(void);
//Глобальные переменные
/********** Главная фунция **********/
void main(void)
{
//Инициализация входов/выходов
init_IO();
//Процедура инициализации ТС1
init_TC1();
//Инициализация локальных переменных
//Значение числа с 12-битного входа
unsigned int data_input = 0;
//Значения с соотв. входов
unsigned char data_in_D, data_in_B = 0;
//Разрешение прерываний
sei();
//Рабочий цикл
while(1)
{
//Читаем значения со входов
//Порт D без изменений
data_in_D = PIND;
//Порт B с очисткой неиспользуемых младших битов
data_in_B = PINB & ((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
//Преобразуем их в 10-битное число
data_input = ((data_in_B << 4) | data_in_D) >> 2;
//Выдаем заданную скважность ШИМ
OCR1A = data_input;
};
}
/********** Функции **********/
//Процедура инициализации входов/выходов
void init_IO(void)
{
//12-битный вход, собранный из входов портов D и B
//Младшие биты входа 7-0 (порт D)
DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0));
//Старшие биты входа 11-8 (порт B)
DDRB &= ~((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
//Подтягиваем входы к единице
PORTD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0);
PORTB |= (1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4);
//Тестовый выход
DDRB |= (1 << PB0);
}
//Процедура инициализации ТС1 (формирование выходного аналогового напряжения)
void init_TC1(void)
{
//Вывод PB1 (OC1A) - выход ШИМ
DDRB |= (1 << PB1);
//Сброс в ноль выхода OC1A при совпадении, режим 10-bit FastPWM
TCCR1A |= (1 << COM1A1) | (1 << WGM11) | (1 << WGM10);
//Предделитель 1
TCCR1B |= (1 << WGM12) | (1 << CS10);
//Начальное значение скважности ШИМ
OCR1A = 0;
//Вкл. прерывания по переполнению ТС
TIMSK |= (1 << TOIE1);
}
/********** Векторы прерываний **********/
//Вектор прерывания по переполнению ТС1
ISR(TIMER1_OVF_vect)
{
PORTB ^= (1 << PB0);
}
Вт июн 04, 2019 19:46:29
Вт июн 04, 2019 21:00:05
Вт июн 04, 2019 21:29:27
Варнинги компилятор выдает?baron_P писал(а):Два часа ковырял сегодня и ничего, идеи кончились.
//Преобразуем их в 10-битное число
data_input = ((data_in_B << 4) | data_in_D) >> 2
data_input = (uint16_t) какая-то тестовая константа;
А протеус исполняет то, что скомпиллено.WiseLord писал(а):AVR-libc, конечно, позволяет сразу с 16-битным работать, но кто знает, как это протеус воспринимает...
Вт июн 04, 2019 21:55:08
Starichok51 писал(а):а зачем 12 бит, если они потом обрезаются до 10 бит?
Z_h_e писал(а):Варнинги компилятор выдает?
Вот этоЗаменить например на это
- Код:
//Преобразуем их в 10-битное число
data_input = ((data_in_B << 4) | data_in_D) >> 2Поглядеть на реакцию системы. Сделать какие-то выводы.
- Код:
data_input = (uint16_t) какая-то тестовая константа;
Кстати в протеусе можно и точки останова использовать и смотреть значения переменных и по шагам шагать.
Естественно следует избегать неявного преобразования типов. А протеус исполняет то, что скомпиллено.
Вт июн 04, 2019 22:26:42
OCR1AH = (data_input >> 8);
OCR1AL = (data_input & 0xFF);
Ср июн 05, 2019 08:42:22
OCR1AH = (data_input >> 8);
OCR1AL = (data_input & 0xFF);
void TIM16_WriteOCRA1(unsigned int i)
{
unsigned char sreg;
/* Save Global Interrupt Flag*/
sreg = SREG;
/* Disable interrupts*/
cli();
/* Set OCR1A to i */
OCR1A= i;
/* Restore Global Interrupt Flag*/
SREG = sreg;
}
Ср июн 05, 2019 16:36:24
Ср июн 05, 2019 18:36:11
Нужно подгружать исполняемый код не hex, а elf. Тогда можно будет видеть переменные в отладке на паузе. И еще желательно кинуть исходники в папку с проектом в протеусе, тогда можно и по шагам шагать будет. Я правда очень давно в протеусе симуляцию не делал, может чего не точно сказал. А так да, модели МК для протеуса не без глюков, что-то там в режиме СТС было не так, например.baron_P писал(а):Как посмотреть в Протеусе состояние переменных не разобрался сходу,
Чт июн 06, 2019 14:09:41
/*
МК ATMEGA8
Частота МК = 8 МГц
Fuse High Byte
BODLEVEL = 0 - нижний порог напряжения питания 4 В
BODEN = 0 - слежение за напряжением питания вкл.
SUT1 = 0 \ время включения 6СК + 64 ms
SUT0 = 0 /
CKSEL3 = 0 \
CKSEL2 = 1 - встроенный источник тактовых импульсов
CKSEL1 = 0 - с частотой 8 МГц
CKSEL0 = 0 /
Fuse Low Byte
RSTDISBL = 1 - переназначение вывода ~RESET выкл.
WDTON = 1 - постоянная работа сторожевого таймера выкл.
SPIEN = 0 - внутрисхемное программирование вкл.
CKOPT = 1 - опции работы с внешним кварцевым резонатором выкл.
EESAVE = 1 - защита EEPROM от стирания выкл.
BOOTSZ1 = 0 \ размер загрузочного сектора
BOOTSZ0 = 0 / 1024 слова, начальный адрес $0C00
BOOTRST = 1 - перенос стартового сектора в область загрузчика выкл.
*/
//Подключенные файлы
#include <avr/io.h> // Стандартные функции ввода/вывода для МК
#include <avr/interrupt.h> // Стандартные функции работы с прерываниями
#include <avr/wdt.h> // Стандартные функции работы cо сторожевым таймером
//Подстановки
#define PWM_MAX 4095 // Максимальное значение скважности для 12-битиного ШИМ (PWM_MAX = 2^12 - 1)
#define N_MAX 3 // Максимальное количесво значений для получения средне арифметичесого (2^N_MAX = 8)
#define U_INT_MAX 65535 // Максимальное значение типа unsigned int
//Прототипы функций
//Процедура инициализации входов/выходов
void init_IO(void);
//Процедура инициализации ТС1
void init_TC1(void);
//Процедура записи в 16-битный регистр OCR1A
void WriteToOCRA1(unsigned int);
//Функция получения среднего значения из N_MAX полученных
unsigned int data_conversation(unsigned int, unsigned int);
/********** Главная фунция **********/
void main(void)
{
//Инициализация входов/выходов
init_IO();
//Инициализация ТС1
init_TC1();
//Инициализация локальных переменных
//Значения с входов соотв. портов
unsigned char data_in_D = 0, data_in_B = 0;
//Значение числа с 12-битного входа
unsigned int data_input = 0;
//Вычисленное средне арифметическое из N_MAX полученных значений
unsigned int data_reference = 0;
//Разрешение прерываний
sei();
//Включение сторожевого таймера с периодом 1с
wdt_enable(WDTO_1S);
//Рабочий цикл
while(1)
{
//Чтение значений со входов
//Порт D без изменений
data_in_D = PIND;
//Порт B с очисткой неиспользуемых младших битов
data_in_B = PINB & ((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
//Преобразование полученных значений в 12-битное число (0b00 4бита PortB 8 битов PortD)
data_input = (data_in_B << 4) | data_in_D;
//Получение среднего арифметического из N_MAX значений
data_reference = data_conversation(data_input, data_reference);
//Выдача заданния скважности ШИМ в регистр сравнения
WriteToOCRA1(data_reference);
//Сброс сторожевого таймера
wdt_reset();
};
}
/********** Функции **********/
//Процедура инициализации входов/выходов
void init_IO(void)
{
//12-битный вход, собранный из входов портов D и B
//Младшие биты входа 7-0 (порт D)
DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0));
//Старшие биты входа 11-8 (порт B)
DDRB &= ~((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
//Подтяжка входов к единице
PORTD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0);
PORTB |= (1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4);
//Неиспользуемые выводы назначаются входами
DDRB &= ~((1 << PB3) | (1 << PB2) | (1 << PB0));
DDRC &= ~((1 << PC5) | (1 << PC4) | (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
//Подтяжка неиспользуемых входов к единице
PORTB |= (1 << PB3) | (1 << PB2) | (1 << PB0);
PORTC |= (1 << PC5) | (1 << PC4) | (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0);
}
//Процедура инициализации ТС1 (формирование выходного аналогового напряжения)
void init_TC1(void)
{
//Вывод PB1 (OC1A) - выход ШИМ
DDRB |= (1 << PB1);
//Сброс в ноль выхода OC1A при совпадении, режим FastPWM (ICR1)
TCCR1A |= (1 << COM1A1) | (1 << WGM11);
//Предделитель 1
TCCR1B |= (1 << WGM13) | (1 << WGM12) | (1 << CS10);
//Маскимальное значение скважности
ICR1 = PWM_MAX;
//Начальное (нулевое) значение скважности ШИМ
WriteToOCRA1(0);
}
//Процедура атомарной записи в 16-битный регистр OCR1A (пример из датащита на Atmega8)
void WriteToOCRA1(unsigned int i)
{
unsigned char sreg;
/* Save Global Interrupt Flag*/
sreg = SREG;
/* Disable interrupts*/
cli();
/* Set OCR1A to i */
OCR1A= i;
/* Restore Global Interrupt Flag*/
SREG = sreg;
}
//Функция получения среднего значения из N_MAX полученных
unsigned int data_conversation(unsigned int data_in, unsigned int data_ref)
{
//Суммарное значение N_MAX полученных
static unsigned int data_sum;
//Счетчик количества просуммированых значений
static unsigned char data_n;
//Если количество просуммированных значений меньше заданного
if (data_n < (1 << N_MAX))
{
//Добавляем полученное значение к сумме предыдущих (предельное значени data_in = PWM_MAX*2^N_MAX = 32670)
data_sum += data_in;
//Инкрементируем счетчик полученных значений
data_n++;
}
else
{
//Иначе, обновляем предыдущее средне-арифметическое значение
data_ref = (data_sum >> N_MAX);
//Обнуляем сумму полученных значений
data_sum = 0;
//Обнуляем счетчик полученных значений
data_n = 0;
}
//Возвращаем среднее значение
return data_ref;
}
Чт июн 06, 2019 19:40:33
//Функция получения среднего значения из N_MAX полученных
unsigned int data_conversation(unsigned int data_in, unsigned int data_ref)
Чт июн 06, 2019 19:53:28
baron_P писал(а)://Процедура атомарной записи в 16-битный регистр OCR1A (пример из датащита на Atmega8)
#include <util/atomic.h> /* вот в этом заголовке все нужное */
void WriteToOCRA1(unsigned int i){
ATOMIC_BLOCK(ATOMIC_RESTORSETATE){
OCR1A= i;
}
}