--------------------------
Пишу на Си за еду
Код: Выделить всё
#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 1200000UL
#include<util/delay.h>
#include<avr/pgmspace.h>
#include<avr/sleep.h>
//Prototypes
//This function is called to switch on the LED at the
//Required stage of PWM cycle
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status);
//This function is used to initialise the new PWM cycle
void xyz(void);
volatile unsigned char e;
volatile unsigned char pwm[3]={0,8,8};
volatile unsigned char i=0;
volatile unsigned char k=0;
//PWM scale 0 - On 8 OFF
const unsigned char Blue[15] PROGMEM = {0,8,8,0,0,8,0,6,2,3,6,1,4,5,7};
const unsigned char Red[15] PROGMEM = {8,0,8,2,8,2,0,5,5,5,6,6,6,7,7};
const unsigned char Green[15] PROGMEM = {8,8,0,8,0,0,0,2,0,6,4,2,7,0,2};
volatile unsigned int counter =0;
int main(void)
{
DDRB &= ~((1<<3)|(1<<4)); //Switches and ADC
PORTB |= (1<<3); //Switches
PCMSK = 1<<PCINT3;//Configure PB3 as interrupt
//ADC init
ADMUX = 0b00100010; //ADC2,ADLAR,VCc
ADCSRA = 0b10000010; //prescaled by 4
//neglect first reading
ADCSRA |= 1<<ADSC;
while(ADCSRA&(1<<ADSC));//Wait
i = ADCH;
//Timer Initialisation
TCCR0A = 0x00;
TCCR0B = 0x02;//Prescaling
TIMSK0 = 1<<TOIE0;//Overflow Interrupt Enabled
sei();//Global Interrupts Enabled
while(1)
{
i=0;
ADCSRA |= 1<<ADSC;
while(ADCSRA&(1<<ADSC));//Wait
i = ADCH;
i = i>>4;//Divide by 16
if(i!=15)
{
pwm[0] = pgm_read_byte(&Blue[i]);
pwm[1] = pgm_read_byte(&Red[i]);
pwm[2] = pgm_read_byte(&Green[i]);
counter = 0;
k = 0;
}
_delay_ms(2);//Just a small delay
if(!(PINB&(1<<3)))
{
_delay_ms(30);
while(!(PINB&(1<<3))); //wait
_delay_ms(30);
TIMSK0 &= ~(1<<TOIE0);//Clear timer interrupt
DDRB &=~(1<<0|1<<1|1<<2);
GIFR |= 1<<PCIF;//Clear pending interrupt
GIMSK |= 1<<PCIE;//Pin change interrupt enable
MCUCR |= (1<<SE|1<<SM1);//Power down mode setting
sleep_cpu(); //CPU halted till interrupt
}
}
}
ISR(TIM0_OVF_vect)
{
DDRB &=~(1<<0|1<<1|1<<2);
if(e==8)
{
e=0;
xyz();
}
abc(pwm[0],pwm[1],pwm[2],e);
DDRB |=(1<<0|1<<1|1<<2);
e++;
if(i==15)//Run mode
{
counter++;
if(counter == 390)//500ms
{
counter = 0;
if(k==14)
k=0;
else k++;
pwm[0] = pgm_read_byte(&Blue[k]);
pwm[1] = pgm_read_byte(&Red[k]);
pwm[2] = pgm_read_byte(&Green[k]);
}
}
}
void xyz(void)
{
PORTB |= (1<<0)|(1<<1)|(1<<2);
}
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status)
{
if((status==a))
{
PORTB&= ~(1<<0);
}
if((status==b))
{
PORTB&= ~(1<<1);
}
if((status==c))
{
PORTB&= ~(1<<2);
}
}
ISR(PCINT0_vect)
{
_delay_ms(30);
while(!(PINB&(1<<3))); //wait
_delay_ms(30);
MCUCR = 0x00; //sleep disable
GIMSK &= ~(1<<PCIE);//Pin change interrupt disable
TIMSK0 = 1<<TOIE0;//Overflow Interrupt Enabled
}Код: Выделить всё
DDRB &=~(1<<0|1<<1|1<<2);Код: Выделить всё
abc(pwm[0],pwm[1],pwm[2],e);Код: Выделить всё
DDRB |=(1<<0|1<<1|1<<2);Код: Выделить всё
ISR (TIMER0_OVF_vect) //Прерывание по переполнению Т/С0
/////////////////////////////////////////////////////////////////////////////////////////
//----------------------------П Р Е Р Ы В А Н И Е Т / С 0----------------------------//
/////////////////////////////////////////////////////////////////////////////////////////
{
if(svuntCounterTimer0 == 255)
svuntCounterTimer0 = 0;
else
svuntCounterTimer0++;
TCNT0 = csuchTimer0; //Выставляем счетчик на прервывание по выставленному времени.
}Код: Выделить всё
initTimer0();Код: Выделить всё
size_t a = getTimer0();Код: Выделить всё
volatile uint16_t my_volatile_var;
uint16_t temp;
ATOMIC_BLOCK(ATOMIC_RESTORE_STATE){
tmp = my_volatile_var;
}
if (tmp == 0) ...Я так в С++ пишу. Кстати ARV, я воспользовался твоим советом по поводу QT и Eclipse, сейчас там шпарю свой код. А по поводу uint16_t, буду так теперь делать, если ты говоришь что так грамотней, твой авторитет для меня не оспорим.ARV писал(а):кстати, почему size_t а не uint16_t?
Я получаю из функции getTimer0() значение svuntCounterTimer0, присваиваю его переменной и уже с этой переменной произвожу математические операции.ARV писал(а): где в программе вы ИСПОЛЬЗУЕТЕ значение своей переменной svuntCounterTimer0
Код: Выделить всё
static size_t suntTCObuf = 0; //Буфер значения счетчика таймера
size_t setADC(unsigned char uchADCCannel) //Функция изменения АЦП. Задается номер канала от 0 до 7, возвращается результат измерений (от 1 до 1024) заданного канала.
/////////////////////////////////////////////////////////////////////////////////////////
//------------------------------------S E T A D C------------------------------------//
/////////////////////////////////////////////////////////////////////////////////////////
{
if(!svuntADCTacts) //Если счетчик тактов МК равен 0, то - это начало изменения канала АЦП.
{
unsigned char set_admux = ADMUX; //Присваеваем переменной Регистор настройки канала АЦП
set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));//Обнуляем биты регистра ADMUX
if (uchADCCannel != 0) //Если канал АЦП не равен 0, то...
set_admux |= (1<< (uchADCCannel - 1));//Задаем регистру ADMUX бит канала АЦП
ADMUX = set_admux; //Присваемваем настроенные биты регистру ADMUX
svuntADCTacts = 7;//Иннициализируем счетчик тактов МК расчетной величиной (70 микросекунд)
suntTCObuf = getTimer0(); //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
}
else //Если счетчик тактов не равен 0, значит, производится или завершается измерение АЦП
{
size_t untGetTimer0 = getTimer0(); //Присваеваем значение счетчика таймера Т/С0 переменной
size_t untMinusTimer0 = 0; //Создаем переменную, которая будет хранить колличество времени прошедшего с предыдущего посещения функции
if(untGetTimer0 < suntTCObuf) //Если счетчик таймера Т/С0 обнулился, то...
untMinusTimer0 = 65535 - suntTCObuf + untGetTimer0;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
else//Если нет, то...
untMinusTimer0 = untGetTimer0 - suntTCObuf;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
if (svuntADCTacts <= untMinusTimer0) //Если колличество шагов АЦП будет меньше или равно времени, то...
svuntADCTacts = 0; //Окончание обработки данных каналом АЦП
else //если нет, то...
svuntADCTacts = svuntADCTacts - untMinusTimer0;//Расчитываем счетчик шагов работы АЦП
suntTCObuf = untGetTimer0; //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
if (svuntADCTacts == 0) //Если нулевое значение счетчика тактов МК,то...
return ((ADCL | ADCH << 8) + 1); //Возвращаем значение АЦП +1 (Результат от 1 до 1024). Конец преобразования.
}
return 0; //Возвращаем 0 (т.е. преобразование еще не завершено)
}Код: Выделить всё
#include <avr/io.h>
#include "dc_adc.h" //Загружаем библиотеку настройки АЦП
#define ADC_PORTS 8 //Колличество опрашиваемых каналов АЦП (не больше 8)
int main(void)
{
initADC (); //Запускаем иннициализацию АЦП
unsigned int untADCData = 0; //Переменная, которая будет хранить данные АЦП
unsigned char uncADCPort = 0; //Переменная, которая будет задавать канал АЦП
unsigned int untADCMass[ADC_PORTS]; //Массив данных, в котором будут храниться данные АЦП
for (unsigned char step = 0; step < ADC_PORTS; ++step)//Обуляем массив данных АЦП
untADCMass[step] = 0;
while(1) //Бесконечный цикл
{
untADCData = setADC(uncADCPort); //Самая главная строчка, функция должна всегда быть on-line
if (untADCData > 0) //Если функция возвращает 0, значит результат еще не получен от АЦП, если нет, то...
{
untADCMass[uncADCPort] = untADCData;//Присваеваем результат АЦП
++uncADCPort; //Задаем опрашивание другого канала АЦП
if (uncADCPort >= ADC_PORTS) //Условие не допущения превышения канала АЦП
uncADCPort = 0; //Обнуляем канал АЦП
}
}
}Не знал, спасибо, буду знать и использовать. Но я думаю в этом случае не из за этого, так как unsigned сhar - 8 бит, я изменял на этот тип данной переменной svuntCounterTimer0, все равно происходит ошибка инкрементирования рано или поздно.ARV писал(а):использование volatile переменных неоднобайтного размера - это весьма нехорошо...
Код: Выделить всё
untADCData = setADC(uncADCPort);Код: Выделить всё
if(.......) //Если счетчик тактов МК равен 0, то - это начало изменения канала АЦП.
{
suntTCObuf = getTimer0(); //Заносим значение счетчика таймера Т/С0 в переменную, для следующего расчета времени работы функции
}
else //Если счетчик тактов не равен 0, значит, производится или завершается измерение АЦП
{
size_t untGetTimer0 = getTimer0(); //Присваеваем значение счетчика таймера Т/С0 переменной
size_t untMinusTimer0 = 0; //Создаем переменную, которая будет хранить колличество времени прошедшего с предыдущего посещения функции
if(untGetTimer0 < suntTCObuf) //Если счетчик таймера Т/С0 обнулился, то...
untMinusTimer0 = 65535 - suntTCObuf + untGetTimer0;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
else//Если нет, то...
untMinusTimer0 = untGetTimer0 - suntTCObuf;//Расчитываем время прошедшее с предыдущего посещения функции таким образом
if (svuntADCTacts <= untMinusTimer0) //Если колличество шагов АЦП будет меньше или равно времени, то...
........; //Окончание обработки данных каналом АЦП
else //если нет, то...
.......;//Расчитываем счетчик шагов работы АЦП
}Завтра в железе обязательно проверю и отпишусь. Спасибо.DruidCat писал(а):чтение многобайтной volatile-переменной должно быть атомарным, см. пример моего кода. добавьте внутрь getTimer0() ATOMIC_BLOCK и сообщите результат
а в чем же тогда?DruidCat писал(а): так долго искал ошибку в коде, а оказалась проблема не в нем была.
Код: Выделить всё
uint16_t getTimer0(void)Код: Выделить всё
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
untCounterTimer0Buf = svuntCounterTimer0;
}
возражу:codenamehawk писал(а):По мне так вся функциялишена смысла, вызов функции занимает дополнительное время, если вместо нее просто выполнитьКод: Выделить всё
uint16_t getTimer0(void)возможно код успеет выполниться до очередного прерывания. Тогда и ATOMIC_BLOCK не понадобиться.Код: Выделить всё
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { untCounterTimer0Buf = svuntCounterTimer0; }
Ведь если во время выполнения ваших команд(вызов функции с ATOMIC_BLOCK ), прерывание успеет случиться дважды, вы просто потеряете точность.
(Возможно умный компилятор сам выкинет ненужное.)
Код: Выделить всё
#define F_CPU ........обычно этот макрос передается компилятору в командной строке параметром -D (кстати, так вы можете передать и какой-то свой макрос, если нужно). а вот о том, как этот параметр в командную строку попадает, обычно заботится IDE, а точнее - makefileDruidCat писал(а):А вот интересно, где именно в проекте объявляется макрос?Код: Выделить всё
#define F_CPU ........