#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "oled_ssd1306.h"
uint8_t tiki;// глобальные тики показывает число прерываний с 0 до 256
uint8_t clk;// флаг клика
uint8_t clk1;// флаг клика
uint16_t i;// 16 разрядная переменная ,т.к. АЦП имеет разрядность 10 бит(1024) и 8 бит(255) недостаточно для работы АЦП
void adc_ini (void)
{
/*** Настройка АЦП ***/
ADCSRA |= (1 << ADEN) // Включение АЦП
|(1 << ADPS1)|(1 << ADPS0); // предделитель преобразователя на 8
ADMUX |= (0 << REFS1)|(1 << REFS0) // внешний ИОН
|(1 << MUX0)|(1 << MUX1); // вход PC3
}
void adc (void)
{
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
i = (ADCL|ADCH << 8); // Считываем ADC
if (i > 752)
{
PORTD |= (1<<PD0);
PORTD &= ~(1<<PD1);
}
else
{
PORTD |= (1<<PD1);
PORTD &= ~(1<<PD0);
}
}
void Counter0_init()
{
TCCR1B |= (1 << CS12);//ДЕЛИТЕЛЬ НА 256
//TCCR1B |= (1 << CS10);
TCCR1B &= ~(1 << CS11);
TCCR1B &= ~(1 << WGM10);
TCCR1B &= ~(1 << WGM11);
TCCR1B |= (1 << WGM12);//режим СТС
TCCR1B &= ~(1 << WGM13);
TCCR1A &= ~(1 << COM1A1);
TCCR1A |= (1 << COM1A0);
DDRB |= (1 << PB1);
}
// обработчик прерывания по переполнению. ~61гц ( 122)
ISR(TIMER2_OVF_vect)
{
tiki++;//инкрементируем с каждым прерыванием
}
// инициализация таймера
void timer_ini(void)
{
TCCR2|=(1<<CS22)|(1<<CS21);// запуск таймера 0 с делителем 256
TIMSK|=(1<<TOIE2);// разрешить прерывание по переполнению
}
uint8_t tikies(void) //функция получения тиков(8 битное число прерываний в любой момент)
{
return tiki; //возвращает число прерываний (аналог времени между прерываниями умноженному на их число ,т.е. например при частоте 60гц -имеем
// время между двумя прерываниями 1/60= 17мс и текущее время меняется от 17мс*0 =0 ,до 17*256 =4,2сек)
}
// инициализация блинков
void blink_ini(void)
{
DDRB|=(1<<PB1);
DDRC|=(1<<PC0)|(1<<PC1) |(1<<PC2);
}
void button_KA(void)
{
static uint8_t status, press;// переменная тип static для того ,чтобы сохранять свое значение (полученное в результате переключений в теле этой функции)
//при последующем обращении к этой функции (при последующих иттерациях) ,а не начинать с первоначальгого значения (0) ,как с обычной локальной переменной
uint8_t now=tikies();// получаем текущее время(текущее возвращенного функцией now=tikies() значения переменной тики (8битное значение)
switch (status)
{
case 0:// опрос кнопки
if (!(PINB&(1<<PB0))) // если кнопка нажата
{
status=1;// уходим в статус 1
press=now;// запоминаем время нажатия например 25- это число прерываний (тики) назовем его "press"
}
break;
case 1:// учет времени удеражания кнопки
if (PINB&(1<<PB0))// если кнопка уже отжата
{
if ((uint8_t) (now-press)>=3) clk=1;//NB!!! переменная tiki имеет 8 бит и примерно через каждые 17*256 =4,2сек переполняется ,что вызывает сбой в
//if ((now-press)>=3). чтобы избежать этого объявляем переменную (now-press) как 8 бит ,т.е. if ((uint8_t) (now-press)>=3)
// рассчитываем время удержания кнопки,например после запомненных 25(т.е. press)
//счетчик прераваний увеличился и стал now =press+число прерываний,прошедших после запоминания (что и является временем задержки (now-press)
//в данной строке =3 тика(число прерываний (тики))если этой задержки достаточно поднимаем флаг клика clk
//в случае частоты прерываний 60гц имеем задержку 3*17мс =51мс,что достаточно для антидребезга
status=0;// уходим в статус 0 ( 3x8.2=24.6b ms)
}
break;
}
}
void button_KA1(void)
{
static uint8_t status, press1;
uint8_t now1=tikies();// получаем текущее время
switch (status)
{
case 0:// опрос кнопки
if (!(PINB&(1<<PB3))) // если кнопка нажата
{
status=1;// уходим в статус 1
press1=now1;// запоминаем время нажатия
}
break;
case 1:// учет времени удеражания кнопки
if (PINB&(1<<PB3))// если кнопка уже отжата
{
if ((uint8_t) (now1-press1)>=3) clk1=1; //NB!!! переменная tiki имеет 8 бит и примерно через каждые 17*256 =4,2сек переполняется ,что вызывает сбой в
//if ((now1-press1)>=3). чтобы избежать этого объявляем переменную (now1-press1) как 8 бит ,т.е. if ((uint8_t) (now1-press1)>=3)
// рассчитываем время удержания кнопки, если достаточно поднимаем флаг клика
status=0;// уходим в статус 0
}
else// иначе, кнопка всё еще удерживается
{
if ((uint8_t) (now1-press1)>=61) {
// если удерживается уже достаточно долго,т.е. разница между запомненным press1 и текущим now1 больше или
//равно 61(счетчик тиков)(в этом примере) это и есть длинная задержка .И сейчас поднимается флаг длинного клика clk1=10
clk1=10;// поднимаем флаг длинного клика
status=2;// уходим в статус 2
}
}
break;
case 2:// ждем пока кнопку отпустят
if (PINB&(1<<PB3)) status=0;// когда на пине 1 уходим в статус 0
break;
}
}
uint8_t button_stat(void)//При подъеме флага (clk=1) функция возвращает переменную а=clk,о флаг сбрасывает (clk=0) ,подготавливая к следующему нажатию кнопки
{
uint8_t a=clk;
clk=0;
return a;
}
uint8_t button_stat1(void)
{
uint8_t a=clk1;
clk1=0;
return a;
}
void blink_click_KA(void)
{
static uint8_t status;
uint8_t but=button_stat();// получение событий от кнопки
switch (status)
{
case 0:// светодиод выключен
TCCR1B&=~((1<<CS10)|(1<<CS12)|(1<<CS11));
TCCR1A &= ~(1 << COM1A1);
TCCR1A &= ~(1 << COM1A0);
PORTB&=~(1<<PB1);
oled_gotoxy(0,4);
oled_write(" POSITIV");
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=1;
}
break;
case 1:// светодиод включен
TCCR1A &= ~(1 << COM1A1);
TCCR1A &= ~(1 << COM1A0);
PORTB|=(1<<PB1);
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=2;
}
oled_gotoxy(0,4);
oled_write(" NEGATIV");
break;
case 2:// светодиод мигает
OCR1A = 15625;
Counter0_init();
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=3;
}
oled_gotoxy(0,4);
oled_write(" 1 Hz ");
break;
case 3:// светодиод мигает
OCR1A = 5156;
Counter0_init();
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=4;
}
oled_gotoxy(0,4);
oled_write(" 3 Hz");
break;
case 4:// светодиод
OCR1A =625;
Counter0_init();
oled_gotoxy(0,4);
oled_write(" 25 Hz ");
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=5;
}
break;
case 5:// светодиод
OCR1A =260;
Counter0_init();
oled_gotoxy(0,4);
oled_write(" 60 Hz ");
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=6;
}
break;
case 6:// светодиод
OCR1A =130;
Counter0_init();
oled_gotoxy(0,4);
oled_write(" 120 Hz");
if (but)// если было нажатие меняем статус.
{
if (but==1)
status=0;
}
break;
}
}
void blink_click_KA1(void)
{
static uint8_t status;
uint8_t but1=button_stat1();// получение событий от кнопки
switch (status)
{
case 0:
if (but1)// если было нажатие меняем статус.
{
status=1;
}
PORTC&=~(1<<PC0);
oled_gotoxy(0,1);
oled_write(" OFF ");
break;
case 1:
if (but1)// если было нажатие меняем статус.
{
status=2;
}
PORTC|=(1<<PC0);
oled_gotoxy(0,1);
oled_write(" LOW ");
break;
case 2:
if (but1)// если было нажатие меняем статус.
{
status=3;
}
PORTC&=~(1<<PC0);
PORTC|=(1<<PC1);
oled_gotoxy(0,1);
oled_write(" MIDDLE");
break;
case 3:
if (but1)// если было нажатие меняем статус.
{
status=4;
}
PORTC&=~(1<<PC1);
PORTC|=(1<<PC2);
oled_gotoxy(0,1);
oled_write(" HIGH ");
break;
case 4:
if (but1)// если было нажатие меняем статус.
{
status=1;
}
PORTC&=~(1<<PC2);
oled_gotoxy(0,1);
oled_write(" OFF ");
break;
}
}
int main(void)
{
DDRD|=(1<<PD0)|(1<<PD1);
//timer_counter1_INIT();
adc_ini ();
blink_ini(); // инициализация блинков
timer_ini();// инициализация таймера
sei();// глобально разрешить прерывания
oled_init();
oled_gotoxy(0,0);
while(1)
{
adc ();
oled_font_size(1);
blink_click_KA();
blink_click_KA1();
button_KA();
button_KA1();
}
}
прошло
Я же вас просил вставлять с тегами кода.
Вернитесь обратно и исправьте сообщение
сначала сделал с тремя обратными апострофами, потом нажал наТекст «как есть» (без применения форматирования)
- выделяете весь текст скетча в Arduino IDE
- копируете его в буфер обмена
- в форме ответа здесь нажимаете кнопку </>
- ничего не меняя вставляете скетч в форму ответа с помощью клавиатурной комбинации Ctrl+V
получилось?
Вот так код и должен выглядеть
Да, спасибо.
теперь хорошо бы пояснить, что код делает и в чем проблема
Пример кода для переключения вывода на светодиод с тремя режимами мигания.
Но строки на дисплее мерцают как старая флюоресцентная лампа. Команду очистки
дисплея я не могу применить, т.к. должно быть еще 2 строки от второй switch с другими
параметрами вывода. Поэтому перед каждой строкой в коде стоит заполненный цветом
фона прямоугольник скрывающий предыдущую строку. Если его убрать то мерцание почти незаметно, но происходит наложение строк. И я пока не могу найти способ решения проблемы.
Экран 0.95" ssd1331.
const int button1Pin = 2; // pushbutton 1 pin
const int led1Pin = A0; // LED 1 pin
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>
#define sclk 13//scl
#define mosi 11//sda
#define cs 10//cs
#define rst 9//res
#define dc 8//dc
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);
int iState;
bool bWasPressed; //Variable to see if the buton was pressed
void blink(void)
{
const uint32_t LED_DELAY = 10;
static uint32_t timeLastTransition = 0;
if (millis() - timeLastTransition >= LED_DELAY)
{
digitalWrite(A0, !digitalRead(A0));
timeLastTransition = millis();
}
}
void blink2(void)
{
const uint32_t LED_DELAY2 = 25;
static uint32_t timeLastTransition2 = 0;
if (millis() - timeLastTransition2 >= LED_DELAY2)
{
digitalWrite(A0, !digitalRead(A0));
timeLastTransition2 = millis();
}
}
void blink3(void)
{
const uint32_t LED_DELAY3 = 50;
static uint32_t timeLastTransition3 = 0;
if (millis() - timeLastTransition3 >= LED_DELAY3)
{
digitalWrite(A0, !digitalRead(A0));
timeLastTransition3 = millis();
}
}
void setup()
{
pinMode(button1Pin, INPUT);
pinMode(led1Pin, OUTPUT);
display.begin();
display.fillScreen(RED);
delay(300);
display.fillScreen(GREEN);
delay(300);
display.fillScreen(BLUE);
delay(300);
display.fillScreen(MAGENTA);
delay(300);
display.fillScreen(BLACK);
delay(1000);
//Default to state 0
iState = 0;
bWasPressed = false;
}
void loop()
{
int iBtnState; // variable to hold the pushbutton state
iBtnState = digitalRead(button1Pin);
//Now determine whether I need to change state.
if (iBtnState == 1)
{
//The button is not pressed. If the button was just
//released then go on ahead to the next state.
if (bWasPressed==1)
{
//Yes, the button was just released.
//Move to the next state.
iState++;
iState = iState % 4;
//Reset the button pressed flag.
bWasPressed = false;
}
}
else
{
//The button is pressed, just set the flag.
bWasPressed = true;
}
//Take action depending on the state of the machine.
switch (iState)
{
case 0:
//Turn off all LEDs
digitalWrite(led1Pin, LOW);
display.fillRect(0,25, 120, 32, BLACK);
display.setCursor(2,28);
display.setTextColor("WHITE");
display.setTextSize(2);
display.print("POSITIV");
break;
case 1:
blink();
display.fillRect(0,25, 120, 32, BLACK);
display.setCursor(4,28);
display.setTextColor(BLUE);
display.setTextSize(2);
display.print("NEGATIV");
break;
case 2:
//Turn on second LED
blink2();
display.fillRect(0,25, 120, 32, BLACK);
display.setCursor(4,28);
display.setTextColor(GREEN);
display.setTextSize(2);
display.print("1");
break;
case 3:
//Turn on third LED
blink3();
display.fillRect(0,25, 120, 32, BLACK);
display.setCursor(4,28);
display.setTextColor(RED);
display.setTextSize(2);
display.print("2");
break;
}
}
Потому что вы перерисовываете строчки на экране в каждом цикле программы, даже если они не изменились. Зачем?
Вот например в этом блоке - поместите перерисовывание экрана внутрь условия смены режима if (but1)
- будет мерцать меньше.
Две кнопки (одна последовательно зажигает по одному 3 светодиода; вторая (независимо
от первой)переключает один светодиод в несколько состояний с разной частотой мигания) и плюс АЦП для контроля батареи.
В одном случае при разряде меняет цвет светодиод, в другом на экране появляется предупреж-
дающая строка (пока код для АЦП не показан во второй программе).
Первая программа работает без проблем, может потому, что написана на Си и экран там простой
черно-белый OLED SSD1306
ОК спасибо за помощь, уже поздно будем отдыхать.
Проблема в обоих программах одна и та же - вы обновляете надписи на экране при каждом проходе, а надо это делать только при изменениях.
Щщщикарное чтиво.
Начали с “не могу загрузить скетч в ардуино”, потом резко пошло обсуждение кода.
Так что там с загрузкой скетча в ардуино? Грузится уже?
грузится
И в чем причина была?
Не менял ничего, перегрузил компьютер трижды и заработало. Т.е. работает как и когда захочет. Проверю, на днях, на другом компьютере. Причина вероятно в железе.
Спасибо за поддержку.
Очень интересно - перегрузил компьютер и опять та же проблема.
Жду другой PC.