Чт июн 06, 2019 20:07:54
baron_P писал(а)://Процедура атомарной записи в 16-битный регистр OCR1A (пример из датащита на Atmega8)
Чт июн 06, 2019 20:11:45
конкретно это применение - да, "точно такое же". а что скажете на счет этого:KorbenDallas писал(а):Так что никакого "не так" тут нет.
unsigned int ReadOCRA1(void){
ATOMIC_BLOCK(ATOMIC_RESTORSETATE){
return OCR1A;
}
}
Пт июн 07, 2019 07:30:16
Пт июн 07, 2019 08:15:48
разница очень большая: если вы делаете атомарное ЧТЕНИЕ, то вам придется совершать без этого библиотечного макроса достаточно много "лишних" телодвижений - я привел код функции, возвращающей атомарно считанное значение регистра, попробуйте написать аналог без этого макросаbaron_P писал(а):Но какая разница - в датащите универсальный сишный вариант под любую среду разработки, насколько я понимаю.
да легко! только это будет не среднее за N_MAX семплов, а среднее за N_MAX предыдущих семплов. метод называется "скользящее среднее" и является простейшим вариантом какого-то там КИХ/БИХ (я нихрена в этом не понимаю) фильтра.baron_P писал(а):я ведь не получу новое среднее значение раньше, чем через 2^N_MAX операций
Пт июн 07, 2019 08:32:17
unsigned int TIM16_ReadTCNT1( void )
{
unsigned char sreg;
unsigned int i;
/* Save Global Interrupt Flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Read TCNT1 into i */
i = TCNT1;
/* Restore Global Interrupt Flag */
SREG = sreg;
return i;
}
Пт июн 07, 2019 08:46:28
хотя бы тем, что он в 3 раза объемнее по строкам соответственно, в 3 раза выше вероятность где-то ошибиться.baron_P писал(а):А чем плох этот пример чтения?
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде.baron_P писал(а):мне он не нужен в данном случае - частота входного сигнала очень низкая
Пт июн 07, 2019 09:25:34
хотя бы тем, что он в 3 раза объемнее по строкам соответственно, в 3 раза выше вероятность где-то ошибиться.baron_P писал(а):А чем плох этот пример чтения?
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде.baron_P писал(а):мне он не нужен в данном случае - частота входного сигнала очень низкая
Пт июн 07, 2019 09:37:10
Пт июн 07, 2019 10:11:20
Пт июн 07, 2019 10:16:50
Пт июн 07, 2019 10:24:26
Пт июн 07, 2019 10:47:35
/*
МК 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/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);
//Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ
void data_conv_PWM(unsigned int);
//Функция чтения 12-битного значения задания со входов
unsigned int data_read(void);
/********** Главная фунция **********/
void main(void)
{
//Инициализация входов/выходов
init_IO();
//Инициализация ТС1
init_TC1();
//Инициализация локальных переменных
//Значение числа с 12-битного входа
unsigned int data_input = 0;
//Включение сторожевого таймера с периодом 1с
wdt_enable(WDTO_1S);
//Рабочий цикл
while(1)
{
//Если на входе присутствует сигнал чтения
if (PINB & (1 << PB0))
{
//Чтение 12-битного значения задания со входов
data_input = data_read();
//Получение среднего арифметического из 2^N_MAX значений и выдача его в ШИМ
data_conv_PWM(data_input);
}
//Сброс сторожевого таймера
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), PB0 - вход сигнала чтения
DDRB &= ~((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4) | (1 << PB0));
//Подтяжка входов к единице
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) | (1 << PB0);
//Неиспользуемые выводы назначаются входами
DDRB &= ~((1 << PB3) | (1 << PB2));
DDRC &= ~((1 << PC5) | (1 << PC4) | (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
//Подтяжка неиспользуемых входов к единице
PORTB |= (1 << PB3) | (1 << PB2);
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;
//Начальное (нулевое) значение скважности ШИМ
OCR1A= 0;
}
//Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ
void data_conv_PWM(unsigned int data_in)
{
//Суммарное значение 2^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_sum = (data_sum >> N_MAX);
//Выдача заданния скважности ШИМ в регистр сравнения
OCR1A= data_sum;
//Обнуляем сумму полученных значений
data_sum = 0;
//Обнуляем счетчик полученных значений
data_n = 0;
}
}
//Функция чтения 12-битного значения задания со входов
unsigned int data_read(void)
{
//Значения с входов соотв. портов
unsigned char data_in_D = 0, data_in_B = 0;
//Значение числа с 12-битного входа
unsigned int data_in = 0;
//Чтение значений со входов
//Порт 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_in = (data_in_B << 4) | data_in_D;
//Возвращение полученного 12-битного числа
return data_in;
}
Пт июн 07, 2019 11:03:35
Пт июн 07, 2019 14:00:50
Пт июн 07, 2019 14:35:44
Пт июн 07, 2019 16:33:32
Пт июн 07, 2019 17:25:10
Пн июн 10, 2019 10:11:41
Пн июн 10, 2019 12:16:29
Пн июн 10, 2019 12:46:50