Перейти к содержанию

Вывод данных в прерывании через SPI


RIMUS1989i

Рекомендуемые сообщения

Здравствуйте. Написал код вывода данных посредством SPI в дисплей, обновление дисплея происходит посредством функции "MY9269_Refresh()", если поместить данную функцию вечный цикл main то все работает, но я хочу вывод поместить в прерывание, но там ничего не происходит. Как правильно инициализировать массив с данными и какой тип функции назначить чтобы данные в массиве обновлять в основном цикле, а выводить в прерывании?

Скрытый текст

#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "pins.h"
#include "MY9269.h"
static uint8_t DATA_DISPLAY[DISPLAY_WIDTH][DISPLAY_HEIGHT][3];
  
void MY9269_Init()
{
	OUT(MY9269_MOSI);
	OUT(MY9269_SCK);
	OUT(MY9269_SS);

	CLR(MY9269_MOSI);
	CLR(MY9269_SCK);
	CLR(MY9269_SS);

	SPCR |=	(1<<SPE)|(1<<MSTR);//|(1<<CPHA); //SPI speed = fosc/2 = 20MHz/2
	SPSR |=	(1<<SPI2X);
}

void MY9269_sendData(uint8_t data)
{
	/* Так, как для MY9269 нужны данные 16бит, то мы просто посылаем два раза по 8бит. Младшие 8бит отправляются пустыми.
		Данные отправляются старшим битом вперед. */
	SPDR = data;					// Отправляем старшит байт
	while(!(SPSR & (1<<SPIF)));	
	SPDR = 0;					// Отправляем младший байт
	while(!(SPSR & (1<<SPIF)));
}

void MY9269_sendCommand(uint16_t data)
{
	SPDR = data >> 8;					// Отправляем старшит байт
	while(!(SPSR & (1<<SPIF)));	
	SPDR = data & 0xFF;					// Отправляем младший байт
	while(!(SPSR & (1<<SPIF)));
}

void MY9269_Latch()
{
	SET(MY9269_SS);
	CLR(MY9269_SS);
}

void MY9269_initLatch(uint8_t region)
{
	uint16_t reg = INVERT_BYTE(region);

	SET(MY9269_SS);
	MY9269_sendCommand(reg<<8); // выбираем область 1& 0xC000
	CLR(MY9269_SS);
	for(uint8_t i = 0; i < NUM_MY9269; i++)
		MY9269_sendCommand(COM_MY9269); // Отправляем команду на NUM_MY9269 микросхем
	MY9269_Latch();
}


void MY9269_Refresh()
{
	uint8_t nr = 0; //SCAN_APP_MY9269
	for(uint8_t r = 0; r < NUM_REGION; r++) // Отпраляем данные в области дисплея по порядку NUM_REGION
	{
		MY9269_initLatch(r); // Выбираем область и производим её настройку
		for(uint8_t x = 0; x < SCAN_APP_MY9269; x++) // Отправляем данные в выбраную область SCAN_APP_MY9269
		{
			for(uint8_t i = 0; i < UNUSED_PINS_MY9269; i++)MY9269_sendData(0); // Отправляем 0 на неиспользуемые каналы
			for(uint8_t y = 0; y < DISPLAY_HEIGHT; y++) 
			{
				MY9269_sendData(DATA_DISPLAY[x + nr][y][0]); // Отправляем уровень R
				MY9269_sendData(DATA_DISPLAY[x + nr][y][1]); // Отправляем уровень G
				MY9269_sendData(DATA_DISPLAY[x + nr][y][2]); // Отправляем уровень B
			}
			MY9269_Latch();
		}
		nr = nr + SCAN_APP_MY9269;
	}
	
}

 

основная программа с main

Скрытый текст

#define F_CPU 20000000UL
#include <avr/io.h>
#include <math.h>
#include <util/delay.h>
#include <stdio.h>
#include <inttypes.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <avr/pgmspace.h>

#include "pins.h"
#include "adc.c"
#include "MY9269.c"
#include "display.c"

uint8_t color[3]={0,0,200};
uint8_t color1[3]={252,0,0};
uint8_t peaks_speed=0;
static uint8_t peak[DISPLAY_WIDTH];


void timer_init()
{
	TCCR2B = (1 << CS22) | (0 << CS21) | (1 << CS20);
	TCCR2A = (1 << WGM21);
	OCR2A = 125;                                    // 125000/125 => 1000 polls/sec
	TCNT2 = 0;
	TIMSK2 |= (1 << OCIE2A);                        // Enable timer compare match interrupt
}

ISR (TIMER2_COMPA_vect)
{
	MY9269_Refresh(); // тут не работает
}

int main(void)
{
	adcInit();
	timer_init();
	MY9269_Init();
	
	
	sei();
    while(1)
    {
		
		clear_display();
		getSpData(0);
		peaks_speed==0?peaks_speed = 4:peaks_speed--;
		uint8_t x, xbase;
		uint8_t ybase;
		uint8_t btm=19 ;
		uint8_t val;
		uint8_t max=19;
		
		for (x = 0; x < DISPLAY_WIDTH; x++) { /
			xbase = x ;
			ybase = buf[x] + buf[x + 32];

			val = (ybase < max ? btm - ybase : btm - max);

			if(peaks_speed == 0)peak[x]++;
			if(peak[x]>=val)peak[x]=val;

			//if(peak[x]-->=val)peak[x]=val;
			
			draw_vert_line(xbase, btm, val, color);
			draw_pixel(xbase ,peak[x], color1);
		}
		
		//MY9269_RefreshRegion(2);
		//MY9269_Refresh(); Тут работает
		//_delay_ms(100);*/
    }
}

 

 

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Прервать основную программу, зайти в прерывание и сделать что-то быстрое, например проверить состояние портов, и вернуться в основную программу.

Да я хочу долго сидеть в прерывании, но мне это нужно для эксперимента.

Ссылка на комментарий
Поделиться на другие сайты

29 минут назад, RIMUS1989i сказал:

в прерывание и сделать что-то быстрое

ключевое слово "быстрое"

ставите флаг, а в цикле меин чекаете, если флаг есть рисуете, и сбрасываете.

типа

uint8_t updataFlags = 0;
прерывание() {
	updataFlags |= UPDATE_FLAG_DISP;
}

...
while (1) {
	if (updateFlags & UPDATE_FLAG_DISP) {
       перерисовать()
    }
}

ну или просто без функции прерывания проверяете системнй флаг нужного прерывания если оно есть в АВР, и перерисовываете 

Быстрое - это это то на пару тактов проца)) а не на пару десятков тысяч тактов

Изменено пользователем DrobyshevAlex
Ссылка на комментарий
Поделиться на другие сайты

@Eddy_Em 

Этот проект я перенес на STM32, но с DMA дела не имел. Как правильно организовать это все через DMA, не подскажите?

Скрытый текст

void MY9269_Refresh()
{
	uint8_t nr = 0; //SCAN_APP_MY9269
	for(uint8_t r = 0; r < NUM_REGION; r++) // Отпраляем данные в области дисплея по порядку NUM_REGION
	{
		MY9269_initLatch(r); // Выбираем область и производим её настройку
		for(uint8_t x = 0; x < SCAN_APP_MY9269; x++) // Отправляем данные в выбраную область SCAN_APP_MY9269
		{
			for(uint8_t i = 0; i < UNUSED_PINS_MY9269; i++)MY9269_sendData(0); // Отправляем 0 на неиспользуемые каналы
			for(uint8_t y = 0; y < DISPLAY_HEIGHT; y++) 
			{
				MY9269_sendData(DATA_DISPLAY[x + nr][y][0]); // Отправляем уровень R
				MY9269_sendData(DATA_DISPLAY[x + nr][y][1]); // Отправляем уровень G
				MY9269_sendData(DATA_DISPLAY[x + nr][y][2]); // Отправляем уровень B
			}
			MY9269_Latch();
		}
		nr = nr + SCAN_APP_MY9269;
	}
	
}

 

 

Задача равномерно по времени вызывать MY9269_initLatch(r), после отправлять данные из массива, 

Изменено пользователем RIMUS1989i
Ссылка на комментарий
Поделиться на другие сайты

19 minutes ago, RIMUS1989i said:

не подскажите?

Занятный вопрос, я не понял, что он означает (почему это меня просят не подсказывать?).

Вот так я работаю с экранчиком на MAX7219. Передача данных посредством DMA, если обновил буфер и нужно обновить экран в соответствии с этим, выставляю соответствующее значение конечного автомата. Если у вас буфер обновляется очень часто, можно в КА убрать состояние RELAX и как только отправлен последний байт из буфера экрана, переходить к началу.

Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...
25.03.2021 в 16:36, RIMUS1989i сказал:

void MY9269_sendData(uint8_t data)

вот эту функцию надо вызывать в прерывании

Изменено пользователем ruhi
не все можно рассказать

Можно сделать все! Но чем больше можно, тем больше нельзя!

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • Сказал - сделал! Благодарю! И остальным, у кого Ц4353 может сломаться, данная табличка будет очень полезна!
    • Автору. Никаких тут 250...200 ватт у этой китайской бздюшки нет в помине. Тем паче на таком подобии радиатора Катушки даже на выходе нет-плохо  
    • Повторюсь - НЕТ, так как у вас там крутилки, что приведет к искажениям при работе в мостовой схеме. Если бы вы "могли" то вам нужно было разорвать выход с темброблока и вход усилителей и впаять (можно навесом) вот такую схему:
    • Все верно, вы почти все что нужно сделали.  Только не нужно было добавлять это b=UDR; Сразу после старта сбросить флаг flags = 0; А в основном цикле ждать установки флага FLAG_END_RX. И если он установлен, проверять на совпадение строки в буфере (rx_buf) с вашей строкой (AT+QM \ r \ n .....   .....  AT+MP \ r \ n) При совпадении вызывать выполнение нужного алгоритма.
    • У меня до саба ещё дело не дошло, только сейчас думаю купить амп на полкиловатта, но так можно, при условии, что на входе будет моно, и будет срез частот
    • Про флаг Т: если он не используется в основной программе, а у меня он постоянно в деле. для меня меня отложенная обработка прерывания обычное дело, нужно лишь правильно расставить приоритеты частей программы. И обычное дело: выставляешь частоту задающего генератора побольше, делишь его до получения частоты 1000 Гц каким либо таймером, загоняешь в прерывание с флагом. затем закольцовываешь основную программу с проверкой флага прерывания от таймера 1000Гц. загоняешь программу в Sleep. Получаешь кольцо обработки с образцовым интервалом в 1 мс. После любого прерывания проверяешь флаг от таймера, если он, то сбрасываешь флаг и начинаешь перебирать подпрограммы обработки индикаторов, клавиатуры, и тд. и тп, подпрограммы обработки флагов и др. После окончания обработки всех подпрограмм возвращаешься к Sleep. И так по кольцу. Если происходит прерывание не от таймера, программа выходит из Sleep, проверяется флаг от таймера, если не он (а это не он) обратно к Sleep. В большенстве программ использую этот алгоритм.   GPIOR1 и GPIOR2 в 88 условно можно использовать как флаги, но их адреса больше 0х1Е, на них не распространяются команды cbi, sbi, sbic, sbis, и их сначала нужно загрузить в общий регистр, промодифицировать, и заново сохранить. Эта последовательность длинная, и модифицирует SREG, что сводит на нет работу по сравнению с  классическим GPIOR.
×
×
  • Создать...