еще раз привет, похоже нашел проблему. Когда мы тут с одним из участников подбирали настройки таймеров, чтобы не было мерцания - я их тестировал только на SPI2. Оказывается, Timer3_CH1 несовместим с SPI1. Поменял на CH4 - все заработало.
В твоем примере строчки 88 - 92 нужно заменить вот на эти:
// initialize Timer
Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE);
Timer3.setPeriod(1000); // in microseconds
Timer3.setCompare(TIMER_CH4, 1); // overflow might be small
Timer3.attachInterrupt(TIMER_CH4, ScanDMD);
Подключено по три панели, строчки поменял, даже не компилируется
double_dmd2:21:19: error: no matching function for call to 'SPIClass::SPIClass(int)'
In file included from C:\Arduino\arduino-1.8.9\libraries\DMD_STM32-master/DMD_STM32.h:37:0,
from C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:13:
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass()
class SPIClass {
^
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate expects 0 arguments, 1 provided
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(const SPIClass&)
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'const SPIClass&'
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(SPIClass&&)
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'SPIClass&&'
double_dmd2:22:20: error: no matching function for call to 'SPIClass::SPIClass(int)'
In file included from C:\Arduino\arduino-1.8.9\libraries\DMD_STM32-master/DMD_STM32.h:37:0,
from C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:13:
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass()
class SPIClass {
^
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate expects 0 arguments, 1 provided
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(const SPIClass&)
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'const SPIClass&'
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(SPIClass&&)
C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'SPIClass&&'
double_dmd2:34:19: error: 'PB11' was not declared in this scope
C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:40:9: note: in expansion of macro 'DMD_PIN_A'
double_dmd2:35:19: error: 'PB10' was not declared in this scope
C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:40:20: note: in expansion of macro 'DMD_PIN_B'
double_dmd2:45:22: error: 'PA8' was not declared in this scope
C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:49:34: note: in expansion of macro 'DMD2_PIN_nOE'
double_dmd2:46:23: error: 'PB8' was not declared in this scope
C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:49:48: note: in expansion of macro 'DMD2_PIN_SCLK'
C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino: In function 'void setup()':
double_dmd2:94:5: error: 'Timer3' was not declared in this scope
double_dmd2:94:20: error: 'TIMER_CH4' was not declared in this scope
double_dmd2:94:31: error: 'TIMER_OUTPUTCOMPARE' was not declared in this scope
exit status 1
no matching function for call to 'SPIClass::SPIClass(int)'
Работают все три, но как было замечено выше, загораются паразитные пиксели и иногда притормаживает, потом опять бежит нормально. Вечером видео сниму, выложу на Ютуб.
Работают все три, но как было замечено выше, загораются паразитные пиксели и иногда притормаживает, потом опять бежит нормально. Вечером видео сниму, выложу на Ютуб.
понятно. Если видео для меня - можете не снимать :) У меня все так же.
"Притормаживание" как будет время, попытаюсь найти и победить - мне кажется это какая-то простая и глупая ошибка в коде...
Паразитные пиксели убираются работой от стабильного БП (во всяком случае. у меня так)
Дима, а может вывод на матрицу повлиять на работу аппаратного UART1 или UART2 ? пробовал "поженить" ПроМини и stm32 на обоих Serial1 и Serial2, Мастер ПроМини, слэйф stm32, последняя какой-то бред выдает. Думал может сам чего накосячил в коде - проверил на двух мегах все нормально. И если это так , как передать данные от меги в stm-ку по UART или как-то еще? Передаю несколько цифр от 0 до 9, разделенные запятыми. что-то типа этого
Напиши подробнее, что именно не работает, я пока не очень понимаю. То, что СТМ32 слишком быстро читает символы - мешать не должно, гораздо хуже когда приемник не успевает.
Я сейчас до завтрашнего вечера уеду, но если ты напишешь - я завтра посмотрю.
Отключил прерывания по таймеру на момент начала приема сигнала по UART, и заново их подключил после приема, данные получил правильные, теперь посмотрю, как это отразиться на вывод на табло...
с пробелами 24 байта, Дима напиши мне на почту, пож.
я что-то адреса теперь не вижу, а вроде днем был. И еще ты днем коды выкладывал - я с телефона заходил, видел. А домой приехал, захожу в конфу - кодов уже нет. Что случилось? Решил вопрос сам?
почта МойНик@mail.ru. Решил можно сказать с костылем(#66), естественно, когда отключаю прерывания, экран дергается.Код подправленный, могу выложить только вечером, т.к он на домашнем компе.Ты на почту мне обязательно напиши.
#include <IRremote.h>
#include <EEPROM.h>
//#include <EasyTransfer.h>
//
////create object
//EasyTransfer ET;
//
//struct SEND_DATA_STRUCTURE{
// //put your variable definitions here for the data you want to send
// //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
// byte Send_rejim;
// byte Send_Rub_Kop[12];
//};
//
////give a name to the group of data
//SEND_DATA_STRUCTURE mydata;
IRrecv irrecv(12); // Указываем пин, к которому подключен приемник
decode_results results;
byte rejim=0;
byte Oldrejim=0;
byte Total_DISPLAYS=3; // всего Экранов 2х3 максимум 7
byte Rub_Kop[12]; // массив со значениями рублей и копеек
void readSet(){
if (Total_DISPLAYS>7 || Total_DISPLAYS<1){
Total_DISPLAYS=1; EEPROM.write(50, 3); // в 50-й ячейке храним кол-во экранов
}else {
// Total_DISPLAYS= EEPROM.read(50); // еще надо сделать ввод кол-ва экранов
}
//первый запуск
for (byte i =0; i < (Total_DISPLAYS*4); i++){
Rub_Kop[i] = EEPROM.read(i);
if (Rub_Kop[i]>9) {Rub_Kop[i]=8;EEPROM.write(i, Rub_Kop[i]);}
}
//первый запуск
}
void setup()
{
Serial.begin(9600); // Выставляем скорость COM порта
// ET.begin(details(mydata), &Serial);
irrecv.enableIRIn(); // Запускаем прием
readSet();
rejim=0;
delay(2000); // подождем пока stm32 загрузиться
SendData();
}
void SendData(){
String dataSennd;
// mydata.Send_rejim = rejim;
//send the data
dataSennd=rejim;
// Serial.print(rejim);
// Serial.print(",");
for (byte i =0; i < (Total_DISPLAYS*4); i++){
dataSennd=dataSennd+ ",";
dataSennd=dataSennd+ Rub_Kop[i];
// Serial.print(Rub_Kop[1]);
// mydata.Send_Rub_Kop[i]=Rub_Kop[i];
}
Serial.println(dataSennd);
// ET.sendData();
}
void loop() {
if (irrecv.decode(&results)) // Если данные пришли
{
switch ( results.value ) {
case 0xBC253F00: //меню
// case 0x807F8A75: //меню
// OldKod=0xBC253F00;
rejim=1;
SendData();
break;
case 0x95AFFB4D: //право
// case 0x807F7A85: //право
// OldKod=0x95AFFB4D;
if(rejim>0){
rejim++;
if (rejim>Total_DISPLAYS*4) rejim=1;
}
SendData();
break;
case 0x845E5420: // лево
// case 0x807FB24D: // лево
// OldKod=0x845E5420;
if(rejim>0){
rejim--;
if ( rejim==0) rejim=Total_DISPLAYS*4;
}
SendData();
break;
case 0x5985AF7D: // ок
// case 0x807F827D: // ок
// OldKod=0x5985AF7D;
rejim=0;
SendData();
break;
case 0xEC9A30D9: //верх
// case 0x807F9A65: //верх
// OldKod=0xEC9A30D9;
if(rejim>0){
Rub_Kop[rejim-1]=Rub_Kop[rejim-1]+1;
if (Rub_Kop[rejim-1]>9) Rub_Kop[rejim-1]=0;
EEPROM.write(rejim-1, Rub_Kop[rejim-1]);
}
SendData();
break;
case 0x99247EBA: // низ
// case 0x807FAA55: // низ
// OldKod=0x99247EBA;
if(rejim>0){
Rub_Kop[rejim-1]=Rub_Kop[rejim-1]-1;
if (Rub_Kop[rejim-1]==255) Rub_Kop[rejim-1]=9;
EEPROM.write(rejim-1, Rub_Kop[rejim-1]);
}
SendData();
break;
}
// Serial.print(results.value, HEX);
// Serial.print(" DEC ");
// Serial.println(results.value, DEC);
// Serial.print("rejim ");//Total_DISPLAYS
// Serial.println(rejim);
// Serial.print("Total_DISPLAYS ");//Total_DISPLAYS
// Serial.println(Total_DISPLAYS);
delay(100); //пауза между повторами //
irrecv.resume(); // принимаем следующую команду
}
}
код stm32
/*--------------------------------------------------------------------------------------
0 1 4 6 5 4 3 2 1 0 9 0 1
double_dmd
Using of two instances of DMD class on SPI(1) and SPI(2)
*/
/*--------------------------------------------------------------------------------------
Includes
--------------------------------------------------------------------------------------*/
#include <DMD_STM32.h>
//#include "fonts/SystemFont5x7.h"
#include "st_fonts/Arial_Black_16_ISO_8859_1.h"
#include "st_fonts/UkrRusArial14.h";
//#include "gfx_fonts/GlametrixLight12pt7b.h"
//#include "gfx_fonts/GlametrixBold9pt7b.h"
//#include <EasyTransfer.h>
//
String Str;
String Str2;
const char * msg;
byte rejim = 0;
byte Oldrejim = 0;
byte Total_DISPLAYS = 3; // всего Экранов 2х3 максимум 7
byte Rub_Kop[12]; // массив со значениями рублей и копеек
unsigned long lastMillis = millis();
boolean flag = 0;
boolean clockTime = false; // флаг того что выводим
byte timeRead = 5;
boolean refresh_screen = false;
// We'll use SPI_1 for first DMD and SPI_2 for second
SPIClass dmd_spi(1);
SPIClass dmd_spi2(2);
#define DISPLAYS_ACROSS 3
#define DISPLAYS_DOWN 1
// ----- Select pins for P10 matrix connection ------------
// pins A, B, SCLK may be any digital I/O, pin nOE should be PWM pin as PB1,PA8
// SPI specific pins as CLK and R_DATA has predefined values:
// for SPI(1) CLK = PA5 R_DATA = PA7
// for SPI(2) CLK = PB13 R_DATA = PB15
// --------------------------------------------------------
#define DMD_PIN_A PB11
#define DMD_PIN_B PB10
#define DMD_PIN_nOE PB1
#define DMD_PIN_SCLK PB0
//Fire up the DMD library at first as dmd
DMD dmd(DMD_PIN_A, DMD_PIN_B, DMD_PIN_nOE, DMD_PIN_SCLK, DISPLAYS_ACROSS, DISPLAYS_DOWN, dmd_spi );
#define DMD2_PIN_A PB7
#define DMD2_PIN_B PB6
#define DMD2_PIN_nOE PA8
#define DMD2_PIN_SCLK PB8
// and at second as dmd2
DMD dmd2(DMD2_PIN_A, DMD2_PIN_B, DMD2_PIN_nOE, DMD2_PIN_SCLK, DISPLAYS_ACROSS, DISPLAYS_DOWN, dmd_spi2 );
// --- Define fonts ----
// DMD.h old style font
DMD_Standard_Font UkrRusArial_F(UkrRusArial_14);
// GFX font with sepatate parts for Latin and Cyrillic chars
//DMD_GFX_Font GlametrixL((uint8_t*)&GlametrixLight12pt7b, (uint8_t*)&GlametrixLight12pt8b_rus, 0x80, 13);
/*--------------------------------------------------------------------------------------
Interrupt handler for Timer1 (TimerOne) driven DMD refresh scanning, this gets
called at the period set in Timer1.initialize();
--------------------------------------------------------------------------------------*/
void ScanDMD()
{
dmd.scanDisplayBySPI();
dmd2.scanDisplayBySPI();
}
/*--------------------------------------------------------------------------------------
setup
Called by the Arduino architecture before the main loop begins
--------------------------------------------------------------------------------------*/
int utf8_rus(char* dest, const unsigned char* src) {
uint8_t i, j;
for ( i = 0, j = 0; src[i]; i++) {
if ((src[i] == 0xD0 ) && src[i + 1]) {
dest[j++] = src[++i] - 0x10;
}
else if ((src[i] == 0xD1 ) && src[i + 1]) {
dest[j++] = src[++i] + 0x30;
}
else dest[j++] = src[i];
}
dest[j] = '\0';
return j;
}
void setup(void)
{
Serial2.begin(9600); //тут получаем данные по UART2
Serial.begin(115200);
// Serial.println("Workin....");
// initialize Timer
// Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE);
// Timer3.setPeriod(1000); // in microseconds
// Timer3.setCompare(TIMER_CH1, 1); // overflow might be small
// Timer3.attachInterrupt(TIMER_CH1, ScanDMD);
Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE);
Timer3.setPeriod(3000); // in microseconds
Timer3.setCompare(TIMER_CH4, 1); // overflow might be small
Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterrupt
//clear/init the DMD pixels held in RAM
dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on)
dmd2.clearScreen( true );
for (byte i =0; i < (Total_DISPLAYS*4); i++){
Rub_Kop[i]=8;
}
sendChar(clockTime);
}
/*--------------------------------------------------------------------------------------
loop
Arduino architecture main loop
--------------------------------------------------------------------------------------*/
boolean pech=0;
void sendChar(boolean blinking) {
// dmd.drawChar(const int bX, const int bY, const unsigned char letter, byte bGraphicsMode)
//#define GRAPHICS_NORMAL 0
//#define GRAPHICS_INVERSE 1
//#define GRAPHICS_TOGGLE 2
//#define GRAPHICS_OR 3
//#define GRAPHICS_NOR 4
dmd.selectFont(&UkrRusArial_F);
dmd.setBrightness(2000);
for (byte i = 0; i < (Total_DISPLAYS * 4); i++) {
if (rejim != 0) {
if (rejim == i + 1 && blinking == 1) {
dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, ' ', GRAPHICS_NORMAL);
} else {
dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL);
}
} else {
dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL);
}
}
dmd2.selectFont(&UkrRusArial_F);
dmd2.setBrightness(2000);
for (byte i = 0; i < (Total_DISPLAYS * 4); i++) {
if (rejim != 0) {
if (rejim == i + 1 && blinking == 1) {
dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, ' ', GRAPHICS_NORMAL);
} else {
dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL);
}
} else {
dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL);
}
}
}
void loop(void)
{
if (read_serial()>0){
if (Str.length()>0) {
Timer3.detachInterrupt(TIMER_CH4);//detachInterrupt
}else{
Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterrupt
}
}
if (flag == 0){
lastMillis = millis();
clockTime = !clockTime;
flag = 1;
sendChar(clockTime);
}
if (millis() - lastMillis >= timeRead * 100) {
flag = 0;
}
if(refresh_screen){
process_data();
sendChar(clockTime);
refresh_screen=0;
}
}
boolean read_serial() {
if (Serial2.available() > 0) {
char ByteRead=Serial2.read(); //чтение данных с порта
if (ByteRead==13) { //возврат каретки
analyzer(); //передача данных на обработку
Str="";
} //освобождение буфера
else {
///накопление данных в буфер
// if(ByteRead!=10)Str=Str+char(ByteRead); // символ "новая строка" \n, нам в буффере не нужен
Str=Str+char(ByteRead);
// Str += ByteRead;
return 1;
}
}else{
return 0;
}
}
void analyzer() {
if (Str.length()>0) {
// Serial.print("Str= ");
// Serial.println(Str); // вот тут выводит муть всякую
Str2=Str;
refresh_screen=1;
// msg = Str.c_str(); //преобразовываем массив String в массив char
// sscanf(msg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",//берем в десятичном значении
// rejim,Rub_Kop[0],Rub_Kop[1],Rub_Kop[2],Rub_Kop[3],Rub_Kop[4],Rub_Kop[5],Rub_Kop[6],Rub_Kop[7],Rub_Kop[8],Rub_Kop[9],Rub_Kop[10],Rub_Kop[11] );
// for (byte i =0; i < (Total_DISPLAYS*4); i++){
//Serial.print("Rub_Kop[");
//Serial.print(i);
//Serial.print("]=");
//Serial.print(Rub_Kop[i]);
//Serial.print(" ");
// }
//Serial.println(" ");
} //если буфер не пустой
}
void process_data(){
Serial.println(Str2);
msg = Str2.c_str(); //преобразовываем массив String в массив char
for (byte i =0; i < (Total_DISPLAYS*4); i++){
Serial.print("Rub_Kop[");
Serial.print(i);
Serial.print("]=");
Serial.print(Rub_Kop[i]);
if(i==6){
Serial.println(" ");
}else{
Serial.print(" ");
}
}
}
//Скетч использует 26356 байт (40%) памяти устройства. Всего доступно 65536 байт.
//Глобальные переменные используют 5312 байт (25%) динамической памяти, оставляя 15168 байт для локальных переменных. Максимум: 20480 байт.
А просто без этой библиотеки передается корректно?
Я где-то читал что uart реализован не аппаратно, а программно, в ядре стм32 для ардуино.
Попробуй сначала прерывание остановить, а потом уже проверить uart, так же были проблемы с кодировкой новой строки попробуй выставить символ какой вместо него.
Остановив прерывание передается корректно, но при этом экран дергается. но на это я уже плюнул.
Посмотрел код в сообщении #72
ИМХО, ты зря читаешь из сериала по одному символу. Как только в буфере что-то появилось - читай в буфер не один символ, а все что есть. Если надо, могу поправить твой код (но только вечером)
и вообще сколько панелей можно подключить на каждый spi? подключил 9, изображение мигает... замена digitalWrite в библиотеке на прямую запись в порт решит проблемы?
сколько панелей можно подключить на каждый spi? подключил 9, изображение мигает... замена digitalWrite в библиотеке на прямую запись в порт решит проблемы?
для начала частоту обновления в таймере попробуй поменять
результаты такие: один spi работает устойчиво 9 панелей, до 11 панелей еще кое-как работает, при 12 панелях происходит срыв изображения. обновление таймера 1000 мксек., надо чтобы работало мин 18 панелей, как победить?
результаты такие: один spi работает устойчиво 9 панелей, до 11 панелей еще кое-как работает, при 12 панелях происходит срыв изображения. обновление таймера 1000 мксек., надо чтобы работало мин 18 панелей, как победить?
а что ты туда выводишь? - в смысле строку символов, бегущую строку или статичное изображение?
И еще - попробуй поднять скорость SPI шины - параметр DMD_SPI_CLOCK , примерно 42 строчку файла DMD_STM32.h
изображение статичное, пробовал SPI_CLOCK_DIV4 и SPI_CLOCK_DIV2, существенной разницы нет, работает на 9 панелях, больше уже дрожит изображение, левые пикселы загораются.
Еще вопрос, как правильно остановить прерывания по таймеру, и потом снова их запустить, вот так останавливаю
Timer3.detachInterrupt(TIMER_CH4);
потом снова так:
Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE);
Timer3.setPeriod(1000); // in microseconds
Timer3.setCompare(TIMER_CH4, 1); // overflow might be small
Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterrupt
Обновление библиотеки - версия v0.3.2 (для СТМ32)
(код на Гитхабе, ссылка в первом сообщении)
с подачи lean_74 найдена и исправлена ошибка задания частоты шины SPI, добавлен вывод через DMA(синхронный)
Главное внешнее изменение - скорость вывода на матрицы выросла примерно в 10-12 раз, в режиме бегущей строки полностью исчезли все "притормаживания" текста. Судя по таймингам вывода, библиотека должна без проблем работать с 16 матрицами на канал без заметного замедления другого кода программы.
В ближайшее время планирую выложить версию с асинхронным DMA, что позволит снизить нагрузку на микроконтроллер еще примерно на порядок.
Обновление - версия v0.4.1 (для СТМ32)
(ссылка на гит в первом сообщении)
Основные изменения:
- вывод данных на матрицы через DMA в асинхронном режиме, то есть почти без загрузки микроконтроллера
- проведена работа по устранению мерцаний и паразитной засветки пикселей, для чего увеличена частота ШИМ регулировки яркости матриц
- все настройки таймеров "убраны" внутрь библиотеки, пользователю не нужно ничего настраивать
- восстановлена совместимость с АВР Атмега328(надеюсь :)
Изменения повлекли за собой некоторые изменения в интерфейсе. Для СТМ32 при начале работы с матрицами обязательна функция dmd.init(), вызываемая в setup(). Яркость теперь регулируется от 0 до 255. Подробнее см. примеры.
Важно: Пины n_OE теперь нужно выбирать только из числа тактируемых Timer3 - то есть PB0 PB1 PB5.
Библиотека нуждается в бета-тестерах :) В принципе, по таймингам на осциллографе последние версии выглядят очень неплохо. Теоретически :) на массовой плате blue pill STM32F103C8T6 библиотека должна работать с 30- 40 матрицами на каждом канале. К сожалению, у меня нет достаточного числа матриц, чтобы проверить это вживую. Так что если кто-то захочет сделать свой проект на моей библиотеке - обращайтесь, обещаю авторскую поддержку :)
=== технические детали, можно не читать ===
Каждое сканирование матриц состоит из двух стадий - подготовки данных и передачи. На последней версии 0.4.1 подготовка занимает примерно 15 мкс (+ 3 мкс на каждую следующую панель), передача по SPI - примерно 30 мкс каждая панель (при частоте тактирования SPI 8МГц).
При использовании асинхронного DMA вторая стадия (передача данных) происходит в фоновом режиме, не нагружая контроллер и оставляя его свободным для других задач. Таким образом, при подключении 30 матриц центральный контроллер будет занят около 100 мкс - при сканировании раз в 1мс это всего 10% процессорного времени.
=================================
Версия 0.4 реализует весь ранее задуманный функционал, дальше я намерен сосредоточится на исправлении ошибок и документировании.
Если у кого-то есть предложения - готов выслушать. Если нужно добавить в библиотеку двухцветные и полноцветные матрицы - готов заняться, если кто-то предоставит такие панели :)
Проверено на 42 матрицах. Статичные изображения выводятся отлично, в режиме бегущей строки на не задействованных в данный момент панелях, видна легкая засветка в такт бегущей строки.
Потому как это совершенно чётко - рекламщики, там деньги есть, и не стоит бесплатно халявщиков плодить ;)
Нафиг не сдался рекламщикам DMD, учитывая, что полноценный монохромный контроллер на 20 модулей (в две строки) стоит 3 бакса (меньше 200р). А самый мощный (2048*512 пикселей, то есть 20*5 метров) из мне известных стоит 35$. Это монохром, конечно. Плюс в эти контроллеры встроены часы и поддержка датчика температуры/влажности, то есть даже для часов ДМД не нужен.
ДМД нужен для специализированных табло: весы, ценники, электронная очередь, метеостанция, всякие счетчики, спортивные табло и тому подобное. То есть, где есть необходимость получить откуда то данные и показать их на табло. С этим стандартные контроллеры не справляются.
Уважаемые знатоки....) Пытаюсь вывести текст с stm-ки нопри выводе на экране белеберда. Попробовал writePixel и на экране отобразилась небольшая полоска (диода на 4-5) и так со всем. Линия становиться не 1 пикселем а целым закрашенным прямоугольником и т.д.
Уважаемые знатоки....) Пытаюсь вывести текст с stm-ки нопри выводе на экране белеберда. Попробовал writePixel и на экране отобразилась небольшая полоска (диода на 4-5) и так со всем. Линия становиться не 1 пикселем а целым закрашенным прямоугольником и т.д.
Мало информации - Какой библиотекой выводите, какая матрица, как подключена. И хорошо бы код увидеть
Да, в среде Arduino ide, плата bluepill, камень stm32f103. Что такое аддон не знаю. Сединял как написано в примере в комментариях. Фото приложу чуть позднее. На ардуино работаю редко, так что не знаю что ещё может быт нужно, извиняйте.
Да, в среде Arduino ide, плата bluepill, камень stm32f103. Что такое аддон не знаю. .
"Аддон" - это пакет для Ардуино ИДЕ, который добавляет в Ардуино поддержку не-ардуино плат.. В частности, для СТМ32 есть несколько аддонов - аддон Роджера Кларка STM32duino и аддон от производителя - STM32Genetric
Эта библиотека под STM32duino, под второй аддон ее никто не проверял пока, может не работать
И еще - другие примеры из библиотеки не пробовали?
lean_74 - а сколько матриц всего подключено? Реально по три на каждый канал, как указано в коде?
lean_74 - собрал заново свой макет с матрицами, тестирую - что-то у меня тоже не работает первый SPI. Ни в паре со вторым, ни отдельно
Буду разбираться.
еще раз привет, похоже нашел проблему. Когда мы тут с одним из участников подбирали настройки таймеров, чтобы не было мерцания - я их тестировал только на SPI2. Оказывается, Timer3_CH1 несовместим с SPI1. Поменял на CH4 - все заработало.
В твоем примере строчки 88 - 92 нужно заменить вот на эти:
// initialize Timer Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE); Timer3.setPeriod(1000); // in microseconds Timer3.setCompare(TIMER_CH4, 1); // overflow might be small Timer3.attachInterrupt(TIMER_CH4, ScanDMD);Проверил, теперь все работает.
Отпишись, плиз, о результате.
Подключено по три панели, строчки поменял, даже не компилируется
double_dmd2:21:19: error: no matching function for call to 'SPIClass::SPIClass(int)' In file included from C:\Arduino\arduino-1.8.9\libraries\DMD_STM32-master/DMD_STM32.h:37:0, from C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:13: C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass() class SPIClass { ^ C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate expects 0 arguments, 1 provided C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(const SPIClass&) C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'const SPIClass&' C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(SPIClass&&) C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'SPIClass&&' double_dmd2:22:20: error: no matching function for call to 'SPIClass::SPIClass(int)' In file included from C:\Arduino\arduino-1.8.9\libraries\DMD_STM32-master/DMD_STM32.h:37:0, from C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:13: C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass() class SPIClass { ^ C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate expects 0 arguments, 1 provided C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(const SPIClass&) C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'const SPIClass&' C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: candidate: constexpr SPIClass::SPIClass(SPIClass&&) C:\Arduino\arduino-1.8.9\hardware\arduino\avr\libraries\SPI\src/SPI.h:156:7: note: no known conversion for argument 1 from 'int' to 'SPIClass&&' double_dmd2:34:19: error: 'PB11' was not declared in this scope C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:40:9: note: in expansion of macro 'DMD_PIN_A' double_dmd2:35:19: error: 'PB10' was not declared in this scope C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:40:20: note: in expansion of macro 'DMD_PIN_B' double_dmd2:45:22: error: 'PA8' was not declared in this scope C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:49:34: note: in expansion of macro 'DMD2_PIN_nOE' double_dmd2:46:23: error: 'PB8' was not declared in this scope C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino:49:48: note: in expansion of macro 'DMD2_PIN_SCLK' C:\Users\****\Documents\Arduino\double_dmd2\double_dmd2.ino: In function 'void setup()': double_dmd2:94:5: error: 'Timer3' was not declared in this scope double_dmd2:94:20: error: 'TIMER_CH4' was not declared in this scope double_dmd2:94:31: error: 'TIMER_OUTPUTCOMPARE' was not declared in this scope exit status 1 no matching function for call to 'SPIClass::SPIClass(int)'IDE 1.8.9 , может тут проблема?
lean_74 - судя по выводу ошибок, вы пытаетесь компилировать для платы avr, а это код для СТМ32
пардон, сам заметил поздно, комп глюканул, перегрузил , заработало.
пардон, сам заметил поздно, комп глюканул, перегрузил , заработало.
уточните - работает по три матрицы на каждый канал? А то у меня всего 2 матрицы. тестировать не на чем :)
Работают все три, но как было замечено выше, загораются паразитные пиксели и иногда притормаживает, потом опять бежит нормально. Вечером видео сниму, выложу на Ютуб.
понятно. Если видео для меня - можете не снимать :) У меня все так же.
"Притормаживание" как будет время, попытаюсь найти и победить - мне кажется это какая-то простая и глупая ошибка в коде...
Паразитные пиксели убираются работой от стабильного БП (во всяком случае. у меня так)
Обновил версию на Гитхабе с учетом последних замечаний и исправлений
- добавлен вертикальный скролл с примерами для СТМ и Уно
- исправлены ошибки в примерах
- изменены настройки таймера в примерах для СТМ
О ошибках сообщайте
Дима, а может вывод на матрицу повлиять на работу аппаратного UART1 или UART2 ? пробовал "поженить" ПроМини и stm32 на обоих Serial1 и Serial2, Мастер ПроМини, слэйф stm32, последняя какой-то бред выдает. Думал может сам чего накосячил в коде - проверил на двух мегах все нормально. И если это так , как передать данные от меги в stm-ку по UART или как-то еще? Передаю несколько цифр от 0 до 9, разделенные запятыми. что-то типа этого
Дима, а может вывод на матрицу повлиять на работу аппаратного UART1 или UART2 ?
ну так это ж легко проверить - временно закомментируйте в коде вывод на матрицу и посмотрите, наладится ли Сериал
разобрался, пока мега отправляет очередной символ по Uart-у, stm32 успевает несколько сотен, а может и больше циклов loop() выполнить.
Вопрос остался открытым: Как передать данные с Меги на STM32, при одновременном использоваться двух независимых экземпляров DMD? читаю так
String bufer=""; void setup(){ Serial.begin(9600); Serial.println("duino started"); } void loop(){ read_serial(); } void read_serial() { if (Serial.available() > 0) { char ByteRead=Serial.read(); //чтение данных с порта if (ByteRead==13) { //возврат каретки analyzer(); //передача данных на обработку bufer=""; } //освобождение буфера else { ///накопление данных в буфер if(ByteRead!=10)bufer=bufer+char(ByteRead); // символ "новая строка" \n, нам в буффере не нужен } } } void analyzer() { if (bufer.length()>0) { Serial.println(bufer); } //если буфер не пустой }Дим может все же подскажешь как победить? а я тебе платку такую готовую с часиками пришлю
Напиши подробнее, что именно не работает, я пока не очень понимаю. То, что СТМ32 слишком быстро читает символы - мешать не должно, гораздо хуже когда приемник не успевает.
Я сейчас до завтрашнего вечера уеду, но если ты напишешь - я завтра посмотрю.
Отключил прерывания по таймеру на момент начала приема сигнала по UART, и заново их подключил после приема, данные получил правильные, теперь посмотрю, как это отразиться на вывод на табло...
А какой длины пакет данных, что передаешь?
с пробелами 24 байта, Дима напиши мне на почту, пож.
с пробелами 24 байта, Дима напиши мне на почту, пож.
я что-то адреса теперь не вижу, а вроде днем был. И еще ты днем коды выкладывал - я с телефона заходил, видел. А домой приехал, захожу в конфу - кодов уже нет. Что случилось? Решил вопрос сам?
почта МойНик@mail.ru. Решил можно сказать с костылем(#66), естественно, когда отключаю прерывания, экран дергается.Код подправленный, могу выложить только вечером, т.к он на домашнем компе.Ты на почту мне обязательно напиши.
Ты на почту мне обязательно напиши.
написал
код ПроМини
#include <IRremote.h> #include <EEPROM.h> //#include <EasyTransfer.h> // ////create object //EasyTransfer ET; // //struct SEND_DATA_STRUCTURE{ // //put your variable definitions here for the data you want to send // //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO // byte Send_rejim; // byte Send_Rub_Kop[12]; //}; // ////give a name to the group of data //SEND_DATA_STRUCTURE mydata; IRrecv irrecv(12); // Указываем пин, к которому подключен приемник decode_results results; byte rejim=0; byte Oldrejim=0; byte Total_DISPLAYS=3; // всего Экранов 2х3 максимум 7 byte Rub_Kop[12]; // массив со значениями рублей и копеек void readSet(){ if (Total_DISPLAYS>7 || Total_DISPLAYS<1){ Total_DISPLAYS=1; EEPROM.write(50, 3); // в 50-й ячейке храним кол-во экранов }else { // Total_DISPLAYS= EEPROM.read(50); // еще надо сделать ввод кол-ва экранов } //первый запуск for (byte i =0; i < (Total_DISPLAYS*4); i++){ Rub_Kop[i] = EEPROM.read(i); if (Rub_Kop[i]>9) {Rub_Kop[i]=8;EEPROM.write(i, Rub_Kop[i]);} } //первый запуск } void setup() { Serial.begin(9600); // Выставляем скорость COM порта // ET.begin(details(mydata), &Serial); irrecv.enableIRIn(); // Запускаем прием readSet(); rejim=0; delay(2000); // подождем пока stm32 загрузиться SendData(); } void SendData(){ String dataSennd; // mydata.Send_rejim = rejim; //send the data dataSennd=rejim; // Serial.print(rejim); // Serial.print(","); for (byte i =0; i < (Total_DISPLAYS*4); i++){ dataSennd=dataSennd+ ","; dataSennd=dataSennd+ Rub_Kop[i]; // Serial.print(Rub_Kop[1]); // mydata.Send_Rub_Kop[i]=Rub_Kop[i]; } Serial.println(dataSennd); // ET.sendData(); } void loop() { if (irrecv.decode(&results)) // Если данные пришли { switch ( results.value ) { case 0xBC253F00: //меню // case 0x807F8A75: //меню // OldKod=0xBC253F00; rejim=1; SendData(); break; case 0x95AFFB4D: //право // case 0x807F7A85: //право // OldKod=0x95AFFB4D; if(rejim>0){ rejim++; if (rejim>Total_DISPLAYS*4) rejim=1; } SendData(); break; case 0x845E5420: // лево // case 0x807FB24D: // лево // OldKod=0x845E5420; if(rejim>0){ rejim--; if ( rejim==0) rejim=Total_DISPLAYS*4; } SendData(); break; case 0x5985AF7D: // ок // case 0x807F827D: // ок // OldKod=0x5985AF7D; rejim=0; SendData(); break; case 0xEC9A30D9: //верх // case 0x807F9A65: //верх // OldKod=0xEC9A30D9; if(rejim>0){ Rub_Kop[rejim-1]=Rub_Kop[rejim-1]+1; if (Rub_Kop[rejim-1]>9) Rub_Kop[rejim-1]=0; EEPROM.write(rejim-1, Rub_Kop[rejim-1]); } SendData(); break; case 0x99247EBA: // низ // case 0x807FAA55: // низ // OldKod=0x99247EBA; if(rejim>0){ Rub_Kop[rejim-1]=Rub_Kop[rejim-1]-1; if (Rub_Kop[rejim-1]==255) Rub_Kop[rejim-1]=9; EEPROM.write(rejim-1, Rub_Kop[rejim-1]); } SendData(); break; } // Serial.print(results.value, HEX); // Serial.print(" DEC "); // Serial.println(results.value, DEC); // Serial.print("rejim ");//Total_DISPLAYS // Serial.println(rejim); // Serial.print("Total_DISPLAYS ");//Total_DISPLAYS // Serial.println(Total_DISPLAYS); delay(100); //пауза между повторами // irrecv.resume(); // принимаем следующую команду } }код stm32
/*-------------------------------------------------------------------------------------- 0 1 4 6 5 4 3 2 1 0 9 0 1 double_dmd Using of two instances of DMD class on SPI(1) and SPI(2) */ /*-------------------------------------------------------------------------------------- Includes --------------------------------------------------------------------------------------*/ #include <DMD_STM32.h> //#include "fonts/SystemFont5x7.h" #include "st_fonts/Arial_Black_16_ISO_8859_1.h" #include "st_fonts/UkrRusArial14.h"; //#include "gfx_fonts/GlametrixLight12pt7b.h" //#include "gfx_fonts/GlametrixBold9pt7b.h" //#include <EasyTransfer.h> // String Str; String Str2; const char * msg; byte rejim = 0; byte Oldrejim = 0; byte Total_DISPLAYS = 3; // всего Экранов 2х3 максимум 7 byte Rub_Kop[12]; // массив со значениями рублей и копеек unsigned long lastMillis = millis(); boolean flag = 0; boolean clockTime = false; // флаг того что выводим byte timeRead = 5; boolean refresh_screen = false; // We'll use SPI_1 for first DMD and SPI_2 for second SPIClass dmd_spi(1); SPIClass dmd_spi2(2); #define DISPLAYS_ACROSS 3 #define DISPLAYS_DOWN 1 // ----- Select pins for P10 matrix connection ------------ // pins A, B, SCLK may be any digital I/O, pin nOE should be PWM pin as PB1,PA8 // SPI specific pins as CLK and R_DATA has predefined values: // for SPI(1) CLK = PA5 R_DATA = PA7 // for SPI(2) CLK = PB13 R_DATA = PB15 // -------------------------------------------------------- #define DMD_PIN_A PB11 #define DMD_PIN_B PB10 #define DMD_PIN_nOE PB1 #define DMD_PIN_SCLK PB0 //Fire up the DMD library at first as dmd DMD dmd(DMD_PIN_A, DMD_PIN_B, DMD_PIN_nOE, DMD_PIN_SCLK, DISPLAYS_ACROSS, DISPLAYS_DOWN, dmd_spi ); #define DMD2_PIN_A PB7 #define DMD2_PIN_B PB6 #define DMD2_PIN_nOE PA8 #define DMD2_PIN_SCLK PB8 // and at second as dmd2 DMD dmd2(DMD2_PIN_A, DMD2_PIN_B, DMD2_PIN_nOE, DMD2_PIN_SCLK, DISPLAYS_ACROSS, DISPLAYS_DOWN, dmd_spi2 ); // --- Define fonts ---- // DMD.h old style font DMD_Standard_Font UkrRusArial_F(UkrRusArial_14); // GFX font with sepatate parts for Latin and Cyrillic chars //DMD_GFX_Font GlametrixL((uint8_t*)&GlametrixLight12pt7b, (uint8_t*)&GlametrixLight12pt8b_rus, 0x80, 13); /*-------------------------------------------------------------------------------------- Interrupt handler for Timer1 (TimerOne) driven DMD refresh scanning, this gets called at the period set in Timer1.initialize(); --------------------------------------------------------------------------------------*/ void ScanDMD() { dmd.scanDisplayBySPI(); dmd2.scanDisplayBySPI(); } /*-------------------------------------------------------------------------------------- setup Called by the Arduino architecture before the main loop begins --------------------------------------------------------------------------------------*/ int utf8_rus(char* dest, const unsigned char* src) { uint8_t i, j; for ( i = 0, j = 0; src[i]; i++) { if ((src[i] == 0xD0 ) && src[i + 1]) { dest[j++] = src[++i] - 0x10; } else if ((src[i] == 0xD1 ) && src[i + 1]) { dest[j++] = src[++i] + 0x30; } else dest[j++] = src[i]; } dest[j] = '\0'; return j; } void setup(void) { Serial2.begin(9600); //тут получаем данные по UART2 Serial.begin(115200); // Serial.println("Workin...."); // initialize Timer // Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); // Timer3.setPeriod(1000); // in microseconds // Timer3.setCompare(TIMER_CH1, 1); // overflow might be small // Timer3.attachInterrupt(TIMER_CH1, ScanDMD); Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE); Timer3.setPeriod(3000); // in microseconds Timer3.setCompare(TIMER_CH4, 1); // overflow might be small Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterrupt //clear/init the DMD pixels held in RAM dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on) dmd2.clearScreen( true ); for (byte i =0; i < (Total_DISPLAYS*4); i++){ Rub_Kop[i]=8; } sendChar(clockTime); } /*-------------------------------------------------------------------------------------- loop Arduino architecture main loop --------------------------------------------------------------------------------------*/ boolean pech=0; void sendChar(boolean blinking) { // dmd.drawChar(const int bX, const int bY, const unsigned char letter, byte bGraphicsMode) //#define GRAPHICS_NORMAL 0 //#define GRAPHICS_INVERSE 1 //#define GRAPHICS_TOGGLE 2 //#define GRAPHICS_OR 3 //#define GRAPHICS_NOR 4 dmd.selectFont(&UkrRusArial_F); dmd.setBrightness(2000); for (byte i = 0; i < (Total_DISPLAYS * 4); i++) { if (rejim != 0) { if (rejim == i + 1 && blinking == 1) { dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, ' ', GRAPHICS_NORMAL); } else { dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL); } } else { dmd.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL); } } dmd2.selectFont(&UkrRusArial_F); dmd2.setBrightness(2000); for (byte i = 0; i < (Total_DISPLAYS * 4); i++) { if (rejim != 0) { if (rejim == i + 1 && blinking == 1) { dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, ' ', GRAPHICS_NORMAL); } else { dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL); } } else { dmd2.drawChar(0 + i * 22 + ((i == 2 || i == 6 || i == 10) ? 8 : 0), 0, '0' + Rub_Kop[i], GRAPHICS_NORMAL); } } } void loop(void) { if (read_serial()>0){ if (Str.length()>0) { Timer3.detachInterrupt(TIMER_CH4);//detachInterrupt }else{ Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterrupt } } if (flag == 0){ lastMillis = millis(); clockTime = !clockTime; flag = 1; sendChar(clockTime); } if (millis() - lastMillis >= timeRead * 100) { flag = 0; } if(refresh_screen){ process_data(); sendChar(clockTime); refresh_screen=0; } } boolean read_serial() { if (Serial2.available() > 0) { char ByteRead=Serial2.read(); //чтение данных с порта if (ByteRead==13) { //возврат каретки analyzer(); //передача данных на обработку Str=""; } //освобождение буфера else { ///накопление данных в буфер // if(ByteRead!=10)Str=Str+char(ByteRead); // символ "новая строка" \n, нам в буффере не нужен Str=Str+char(ByteRead); // Str += ByteRead; return 1; } }else{ return 0; } } void analyzer() { if (Str.length()>0) { // Serial.print("Str= "); // Serial.println(Str); // вот тут выводит муть всякую Str2=Str; refresh_screen=1; // msg = Str.c_str(); //преобразовываем массив String в массив char // sscanf(msg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",//берем в десятичном значении // rejim,Rub_Kop[0],Rub_Kop[1],Rub_Kop[2],Rub_Kop[3],Rub_Kop[4],Rub_Kop[5],Rub_Kop[6],Rub_Kop[7],Rub_Kop[8],Rub_Kop[9],Rub_Kop[10],Rub_Kop[11] ); // for (byte i =0; i < (Total_DISPLAYS*4); i++){ //Serial.print("Rub_Kop["); //Serial.print(i); //Serial.print("]="); //Serial.print(Rub_Kop[i]); //Serial.print(" "); // } //Serial.println(" "); } //если буфер не пустой } void process_data(){ Serial.println(Str2); msg = Str2.c_str(); //преобразовываем массив String в массив char for (byte i =0; i < (Total_DISPLAYS*4); i++){ Serial.print("Rub_Kop["); Serial.print(i); Serial.print("]="); Serial.print(Rub_Kop[i]); if(i==6){ Serial.println(" "); }else{ Serial.print(" "); } } } //Скетч использует 26356 байт (40%) памяти устройства. Всего доступно 65536 байт. //Глобальные переменные используют 5312 байт (25%) динамической памяти, оставляя 15168 байт для локальных переменных. Максимум: 20480 байт.А просто без этой библиотеки передается корректно?
Я где-то читал что uart реализован не аппаратно, а программно, в ядре стм32 для ардуино.
Попробуй сначала прерывание остановить, а потом уже проверить uart, так же были проблемы с кодировкой новой строки попробуй выставить символ какой вместо него.
Остановив прерывание передается корректно, но при этом экран дергается. но на это я уже плюнул.
Остановив прерывание передается корректно, но при этом экран дергается. но на это я уже плюнул.
Посмотрел код в сообщении #72
ИМХО, ты зря читаешь из сериала по одному символу. Как только в буфере что-то появилось - читай в буфер не один символ, а все что есть. Если надо, могу поправить твой код (но только вечером)
не одна засада, так другая - это яркость на 20000
а это на 2000
и вообще сколько панелей можно подключить на каждый spi? подключил 9, изображение мигает... замена digitalWrite в библиотеке на прямую запись в порт решит проблемы?
сколько панелей можно подключить на каждый spi? подключил 9, изображение мигает... замена digitalWrite в библиотеке на прямую запись в порт решит проблемы?
для начала частоту обновления в таймере попробуй поменять
результаты такие: один spi работает устойчиво 9 панелей, до 11 панелей еще кое-как работает, при 12 панелях происходит срыв изображения. обновление таймера 1000 мксек., надо чтобы работало мин 18 панелей, как победить?
результаты такие: один spi работает устойчиво 9 панелей, до 11 панелей еще кое-как работает, при 12 панелях происходит срыв изображения. обновление таймера 1000 мксек., надо чтобы работало мин 18 панелей, как победить?
И еще - попробуй поднять скорость SPI шины - параметр DMD_SPI_CLOCK , примерно 42 строчку файла DMD_STM32.h
изображение статичное, пробовал SPI_CLOCK_DIV4 и SPI_CLOCK_DIV2, существенной разницы нет, работает на 9 панелях, больше уже дрожит изображение, левые пикселы загораются.
Еще вопрос, как правильно остановить прерывания по таймеру, и потом снова их запустить, вот так останавливаю
потом снова так:
Timer3.setMode(TIMER_CH4, TIMER_OUTPUTCOMPARE); Timer3.setPeriod(1000); // in microseconds Timer3.setCompare(TIMER_CH4, 1); // overflow might be small Timer3.attachInterrupt(TIMER_CH4, ScanDMD);//detachInterruptне запускаются...
Обновление библиотеки - версия v0.3.2 (для СТМ32)
(код на Гитхабе, ссылка в первом сообщении)
с подачи lean_74 найдена и исправлена ошибка задания частоты шины SPI, добавлен вывод через DMA(синхронный)
Главное внешнее изменение - скорость вывода на матрицы выросла примерно в 10-12 раз, в режиме бегущей строки полностью исчезли все "притормаживания" текста. Судя по таймингам вывода, библиотека должна без проблем работать с 16 матрицами на канал без заметного замедления другого кода программы.
В ближайшее время планирую выложить версию с асинхронным DMA, что позволит снизить нагрузку на микроконтроллер еще примерно на порядок.
Cпасибо lean_74 за тестирование кода
Обновление - версия v0.4.1 (для СТМ32)
(ссылка на гит в первом сообщении)
Основные изменения:
- вывод данных на матрицы через DMA в асинхронном режиме, то есть почти без загрузки микроконтроллера
- проведена работа по устранению мерцаний и паразитной засветки пикселей, для чего увеличена частота ШИМ регулировки яркости матриц
- все настройки таймеров "убраны" внутрь библиотеки, пользователю не нужно ничего настраивать
- восстановлена совместимость с АВР Атмега328(надеюсь :)
Изменения повлекли за собой некоторые изменения в интерфейсе. Для СТМ32 при начале работы с матрицами обязательна функция dmd.init(), вызываемая в setup(). Яркость теперь регулируется от 0 до 255. Подробнее см. примеры.
Важно: Пины n_OE теперь нужно выбирать только из числа тактируемых Timer3 - то есть PB0 PB1 PB5.
Библиотека нуждается в бета-тестерах :) В принципе, по таймингам на осциллографе последние версии выглядят очень неплохо. Теоретически :) на массовой плате blue pill STM32F103C8T6 библиотека должна работать с 30- 40 матрицами на каждом канале. К сожалению, у меня нет достаточного числа матриц, чтобы проверить это вживую. Так что если кто-то захочет сделать свой проект на моей библиотеке - обращайтесь, обещаю авторскую поддержку :)
=== технические детали, можно не читать ===
Каждое сканирование матриц состоит из двух стадий - подготовки данных и передачи. На последней версии 0.4.1 подготовка занимает примерно 15 мкс (+ 3 мкс на каждую следующую панель), передача по SPI - примерно 30 мкс каждая панель (при частоте тактирования SPI 8МГц).
При использовании асинхронного DMA вторая стадия (передача данных) происходит в фоновом режиме, не нагружая контроллер и оставляя его свободным для других задач. Таким образом, при подключении 30 матриц центральный контроллер будет занят около 100 мкс - при сканировании раз в 1мс это всего 10% процессорного времени.
=================================
Версия 0.4 реализует весь ранее задуманный функционал, дальше я намерен сосредоточится на исправлении ошибок и документировании.
Если у кого-то есть предложения - готов выслушать. Если нужно добавить в библиотеку двухцветные и полноцветные матрицы - готов заняться, если кто-то предоставит такие панели :)
Проверено на 42 матрицах. Статичные изображения выводятся отлично, в режиме бегущей строки на не задействованных в данный момент панелях, видна легкая засветка в такт бегущей строки.
Потому как это совершенно чётко - рекламщики, там деньги есть, и не стоит бесплатно халявщиков плодить ;)
Нафиг не сдался рекламщикам DMD, учитывая, что полноценный монохромный контроллер на 20 модулей (в две строки) стоит 3 бакса (меньше 200р). А самый мощный (2048*512 пикселей, то есть 20*5 метров) из мне известных стоит 35$. Это монохром, конечно. Плюс в эти контроллеры встроены часы и поддержка датчика температуры/влажности, то есть даже для часов ДМД не нужен.
ДМД нужен для специализированных табло: весы, ценники, электронная очередь, метеостанция, всякие счетчики, спортивные табло и тому подобное. То есть, где есть необходимость получить откуда то данные и показать их на табло. С этим стандартные контроллеры не справляются.
b707, я желаю с тобой пообщаться, но нигде не нашел контактов.
Черкни мне на evgeny_fox@mail.ru если не трудно
Уважаемые знатоки....) Пытаюсь вывести текст с stm-ки нопри выводе на экране белеберда. Попробовал writePixel и на экране отобразилась небольшая полоска (диода на 4-5) и так со всем. Линия становиться не 1 пикселем а целым закрашенным прямоугольником и т.д.
Мало информации - Какой библиотекой выводите, какая матрица, как подключена. И хорошо бы код увидеть
Библиотека предоставленая в 1 сообщении.
Матрица p10 32x16.Код - пример dmd_demo
СТМ32 в среде Ардуино? - какеой аддон установлен?
Попытайтесь более расширено сформулировать проблему... ну если хотите ее решить, конечно.
Пока же я могу только ответить в вашем же лаконичном стиле - у меня этот пример отлично работает.
Да, в среде Arduino ide, плата bluepill, камень stm32f103. Что такое аддон не знаю. Сединял как написано в примере в комментариях. Фото приложу чуть позднее. На ардуино работаю редко, так что не знаю что ещё может быт нужно, извиняйте.
"Аддон" - это пакет для Ардуино ИДЕ, который добавляет в Ардуино поддержку не-ардуино плат.. В частности, для СТМ32 есть несколько аддонов - аддон Роджера Кларка STM32duino и аддон от производителя - STM32Genetric
Эта библиотека под STM32duino, под второй аддон ее никто не проверял пока, может не работать
И еще - другие примеры из библиотеки не пробовали?
Перепробовал все примеры. Везде кроме dmd_demo чёрный экран. Аддон STM32duino
Вот это выдает dmd_demo
если готовы подождать - вечером попробую
Не плохо бы еще модуль сфоткать с другой стороны, и чипы.
В китайских контроллерах режимов сканирования штук 50+ точно есть.
судя по всему - самая распространенная одноцветная 1/4 скан, HUB12
Должна работать.
этикетку еще сфоткайте на всякий случай