Указатели в функции
- Войдите на сайт для отправки комментариев
Понадобилась помощь.
Есть дисплей Nokia 1616. цветной 132х162 точки
Интерфейс 9бит SPI
Так как стандартный SPI 8 бит, первый бит бит передается ногодрыганьем, а остально по SPI
Все работает, но медленно
На данный момент скорость зарисовки всего дисплея одним цветом удалось поднять с 0,74 кадра/сек до 3,37 кадра/сек. больше улучшить не получается
я бы успокоился, но нашел библиотеку которая делает почти 18 кадров/сек
и там везде используются указатели
так как я с ними не умею работать, и чтение различной литературы особо ясности не добавило, прощу объяснить как сделать максимальное быстродействие
в основном коде происходит вызов функции, которая например рисует пиксель
в функцию передаем цвет 16бит и сколько раз рисовать
но когда просто передаем мы из одной ячейки оперативной памяти копируем в другую и обрабатываем
но с помощью указателей можно обрабатывать не копируя, а через указатель обратится к самому исходному числу
//==============================================================================================
// Вывод на дисплей 8 бит данных или комманд
//==============================================================================================
void lcd_write(byte mode, byte c){
//dWrite(CS, 0);
(mode)? dWrite(DAT, 1) : dWrite(DAT, 0);
dWrite(CLK, 1);
dWrite(CLK, 0);
SPI_HW_ON;
SPDR = c;
SPI_HW_WAIT;
SPI_HW_OFF;
}
//==============================================================================================
// Вывод на дисплей 16 бит данных
//==============================================================================================
void lcd_write16(unsigned int dat){
lcd_write(DATA,dat>>8);
lcd_write(DATA,dat);
}
void fill_screen(unsigned int color){ lcd_write(CMD,0x2A); //x-координата lcd_write16(2); lcd_write(CMD,0x2B); //Y-координата lcd_write16(1); lcd_write(CMD,0x2C); for (byte i=0; i<DISP_H; i++){ for(byte j=0;j<DISP_W;j++){ lcd_write16(color); } } }ну и в основной вызываем
Если нужно передать только одно число, то указатель не поможет. Указатель нужен, когда нужно передать множество чисел, расположенных в непрерывной области памяти. Можно исходить ихз следующей логики:
1. Передаем как число. Это значит это число и будет считано в регистр и использовано.
2. Передаем как указатель. Это значит, что указатель будет помещен в регистры, затем будет считано это число из памяти.
Либо я не понял Вашего вопроса.
Можно попробовать выделить в куче область видеопамяти где разные функции будут оперировать с общтми данными без копирования
Попробуйте для начала работаь только с глобальными переменными, вместо того, чтобы гонять их из функции в функцию. Если будет реальное улучшение быстродействия, то можно заменить все это на указатели в качестве параметров. У меня по крайней мере есть большие сомнения, что проблема решится именно указателями, тут наверняка еще и сам алгоритм в "быстрой" библиотеке просто очень хорошо оптимизирован.
всё упирается в SPI, где один бит ногодрыгание... это и есть ограничение... никаких 18 кадров/с быть не может. И кстати, у 1616 160 на 128 точек, а не та херня что вы написали.
__Alexander не знаешь лучше молчи. тебе код дать где это работает?
toly я уже честно сказать и не знаю, выложе исходный код где все быстро и сами увидите
там короче создается массив при заливке экране размеров в одну строку и из него через указатели выводят. наверно в этом дело
повырезал сколько получилось из либы лишнее, там было на 3 дисплея
CPP
#include "LCD.h" #include "Arduino.h" #include <avr/pgmspace.h> void SpiCmd(u8 c); void SpiData(u8 c); #define DELAY_MS 0x200 #ifndef abs #define abs(_x) ((_x) < 0 ? -(_x) : (_x)) #endif #ifndef max #define max(_a,_b) (((_a) > (_b)) ? (_a) : (_b)) #define min(_a,_b) (((_a) < (_b)) ? (_a) : (_b)) #endif LCDInfo _lcd; // LCD info for detected screen void Cmd1616(u8 cmd, int a, int b){ SpiCmd(cmd); SpiData(a>>8); SpiData(a); SpiData(b>>8); SpiData(b); } //================================================================================= #if 0 void FillGeneric(int color, u32 count){ u8 a = (color >> 8); u8 b = color; if (count <= 0) return; while (count--) { SpiData(a); SpiData(b); } } void BlitGeneric(const u8* data, u32 count) { if (count <= 0) return; while (count--) { SpiData(*data++); SpiData(*data++); } } void BlitIndexedGeneric(const u8* data, const u8* palette, u32 count) { if (count <= 0) return; while (count--) { int i = *data++; i += i; SpiData(palette[i]); SpiData(palette[i+1]); } } #else #define SPI_HW_OFF SPCR = 0; #define SPI_HW_ON SPCR = _BV(MSTR) | _BV(SPE); #define SPI_HW_WAIT while (!(SPSR & _BV(SPIF))); #define MOSI 11 #define SCK 13 #define SSEL 10 #define MOSI0 dWrite(MOSI,0) #define MOSI1 dWrite(MOSI,1) #define SCK0 dWrite(SCK,0) #define SCK1 dWrite(SCK,1) #define SSEL0 dWrite(SSEL,0) #define SSEL1 dWrite(SSEL,1) void dWrite(u8 pin, u8 val){ u8 bit = digitalPinToBitMask(pin); volatile u8 *out; out = portOutputRegister(digitalPinToPort(pin)); if (val == LOW) *out &= ~bit; else *out |= bit; } void LCDInitHW(){ SSEL1; MOSI1; SCK0; pinMode(MOSI, OUTPUT); pinMode(SCK, OUTPUT); pinMode(SSEL, OUTPUT); } void SpiCmd(u8 d){ MOSI0; SCK1; SCK0; SPI_HW_ON; SPDR = d; SPI_HW_WAIT; SPI_HW_OFF; } void SpiData(u8 d){ MOSI1; SCK1; SCK0; SPI_HW_ON; SPDR = d; SPI_HW_WAIT; SPI_HW_OFF; } #define nop() __asm__ __volatile__("nop") // Fill a 16 bit color // Blit 16 bit pixels // Blit 8 bit indexed pixels from palette // 400,000 pixels/sec on a 16Mhz AVR for Solid fills and 16bpp blits // 380,000 pixels/sec for indexed blits void FillBlit(u32 color, u32 count, const u8* data = 0, const u8* palette = 0) { PORTB |= (1<<3); // MOSI = 1 = Data u8 sck0 = PORTB & ~(1<<5); // SCK u8 sck1 = PORTB | (1<<5); // out is 1 clock vs sbi at 2 SPSR |= 1; // 2x clock u8 a,b; // Handle 16 bit blits and index mode signed char x = 0; u8 y; const u8* p = 0; if (data){ a = *data++; x = 1; if (palette){ p = palette + ((*data++) << 1); a = p[0]; b = p[1]; x = -1; y = 0; } } else{ a = color >> 8; b = color; } count <<= 1; int loop = count >> 8; u8 c = count; if (c) loop++; while (loop){ for (;;){ SPCR = 0; // Turn off SPI HW PORTB = sck1; PORTB = sck0; // Clock MOSI 1 bit to signify data on 9 bit spi SPCR = _BV(MSTR) | _BV(SPE); // SPI Master SPDR = a; // Now we have 16 clocks to kill // 16 clocks to do fill, blit or indexed blit // Indexed blit - 380k if (x < 0){ if ((y^=1)){ a = b; p = palette + ((*data++) << 1); if (--c) continue; // Early out } else { a = p[0]; b = p[1]; if (--c) continue; // Early out } break; } if (x){ // Blit a = *data++; nop(); nop(); // 400k } else{ // Solid Fill u8 t = a; // swap pixel halves a = b; b = t; nop(); nop(); // 400k } if (!--c) break; // 5 }; // loop takes 3 clocks c = 0; loop--; while (!(SPSR & _BV(SPIF))); // wait for last pixel } SPCR = 0; } void FillGeneric(u32 color, u32 count){ FillBlit(color,count); } void BlitGeneric(const u8* data, u32 count) { FillBlit(0,count,data); } void BlitIndexedGeneric(const u8* data, const u8* palette, u32 count) { FillBlit(0,count,data,palette); } #endif void RectangleGeneric(int x, int y, int width, int height, int color) { int right = x + width; if (x < 0) x = 0; if (right > _lcd.width) right = _lcd.width; width = right - x; if (width <= 0) return; int bottom = y + height; if (y < 0) y = 0; if (bottom > _lcd.height) bottom = _lcd.height; height = bottom - y; if (height <= 0) return; _lcd.SetBounds(x,y,width,height); _lcd.Fill(color,width*((long)height)); } void InitGeneric(const short* data, int count){ while (count--){ int b = pgm_read_word(data++); if (b == DELAY_MS){ b = pgm_read_word(data++); delay(b); count--; } else{ if (b > 0xFF) SpiData(b); else SpiCmd(b); } } } //================================================================================= //================================================================================= // SPFD54124B Orise // 132x162 TFT RDID is 0x38 0x84 0x4F // Nokia 6060 6101 6125 5200 6070 0.5mm connector // Nokia 2630 2760 Side 0.4mm connector // Nokia 3500 top static const short _initSPFD54124B[] PROGMEM ={ 0xBA, 0x107, 0x115, // Data Order 0x25, 0x13F, // Contrast 0x11, // Sleep Out 0x13, // Display Normal mode 0x37,0x100, // VSCROLL ADDR 0x3A,0x105, // COLMOD pixel format 4=12,5=16,6=18 0x29, // DISPON 0x20, // INVOFF 0x13, // NORON }; void InitSPFD54124B(){ InitGeneric(_initSPFD54124B,sizeof(_initSPFD54124B)/2); SpiCmd(0x2D); int i; for (i = 0; i < 32; i++) SpiData(i<<1); for (i = 0; i < 64; i++) SpiData(i); for (i = 0; i < 32; i++) SpiData(i<<1); } void SetBoundsSPFD54124B(int x, int y, int width, int height){ Cmd1616(0x2A,x,x+width-1); // column start/end Cmd1616(0x2B,y,y+height-1); // page start/end SpiCmd(0x2C); // RAMWR } #if 1 u8 _gray = 0; u8 _prnd = 0; // 65k period u16 xor16(void) { static u16 y16 = 0xC0ED; y16 ^= (y16 << 1); y16 ^= (y16 >> 1); return y16 ^= (y16 << 14); } // 128 bit period. Nice u32 xor128(void) { static u32 x = 123456789; static u32 y = 362436069; static u32 z = 521288629; static u32 w = 88675123; u32 t; t = x ^ (x << 11); x = y; y = z; z = w; return w = w ^ (w >> 19) ^ t ^ (t >> 8); } #endif #define RNDOM xor128 #define SWAP(_a,_b) { _a = _a ^ _b; _b = _a ^ _b; _a = _a ^ _b; } //================================================================================= //================================================================================= void LCDBegin(){ // Select LCD{ SSEL0; } /* void LCDEnd(){ // Release LCD if (_lcd.format == 1){ BlitMono(); memset(_mono,0,sizeof(_mono)); } SSEL1; } */ int LCDInit(){ LCDInitHW(); delay(120); // Too long? SSEL0; SpiCmd(0x11); // SLEEPOUT delay(120); // Too long? SSEL1; delay(100); // too short? LCDInfo* info = &_lcd; info->Fill = FillGeneric; info->Blit = BlitGeneric; info->BlitIndexed = BlitIndexedGeneric; info->Rectangle = RectangleGeneric; info->width = 132; info->height = 162; info->format = 16; SCK0; SSEL0; InitSPFD54124B(); info->SetBounds = SetBoundsSPFD54124B; SSEL1; SSEL0; }H файл
/* Copyright (c) 2010, Peter Barrett ** ** Permission to use, copy, modify, and/or distribute this software for ** any purpose with or without fee is hereby granted, provided that the ** above copyright notice and this permission notice appear in all copies. ** ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR ** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES ** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ** SOFTWARE. */ #ifndef u8 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; #endif #define DELAY_MS 0x200 typedef void (*LCDRectangleProc)(int x, int y, int width, int height, int color); typedef void (*LCDSetBoundsProc)(int x, int y, int width, int height); typedef void (*LCDFillProc)(u32 color, u32 count); typedef void (*LCDBlitProc)(const u8* data, u32 count); typedef void (*LCDBlitIndexedProc)(const u8* data, const u8* palette, u32 count); typedef void (*LCDScrollProc)(int y); typedef struct { u32 id; int width; int height; int format; int feature; LCDRectangleProc Rectangle; LCDSetBoundsProc SetBounds; LCDFillProc Fill; LCDBlitProc Blit; LCDBlitIndexedProc BlitIndexed; LCDScrollProc Scroll; } LCDInfo; u32 LCDReadID(); int LCDInit(); void LCDBegin(); // Select LCD void LCDEnd(); // Release LCD u32 LCDChanged(); void LCDLine(int x0, int y0, int x1, int y1, int color); #define LCDWidth() _lcd.width #define LCDHeight() _lcd.height #define LCDFormat() _lcd.format #define LCDRectangle _lcd.Rectangle #define LCDSetBounds _lcd.SetBounds #define LCDFill _lcd.Fill #define LCDBlit _lcd.Blit #define LCDBlitIndexed _lcd.BlitIndexed #define LCDScroll _lcd.Scroll #define LCDID() _lcd.id extern LCDInfo _lcd;и код для иде
#include <LCD.h> unsigned long time; unsigned long time2; void setup(){ LCDInit(); Serial.begin(9600); } u16 xor16(void); void Draw8(int cx, int cy, int x, int y, int color) { LCDRectangle(cx-y,cy-x,y<<1,1,color); LCDRectangle(cx-x,cy-y,x<<1,1,color); LCDRectangle(cx-x,cy+y,x<<1,1,color); LCDRectangle(cx-y,cy+x,y<<1,1,color); } // Octant circle drawing void Circle(int cx, int cy, int radius, int color){ int error = -radius; int x = radius; int y = 0; // draws in 4 strips from top down and middle up + reflection about y while (x >= y){ Draw8(cx, cy, x, y,color); error += y; ++y; error += y; if (error >= 0){ --x; error -= x<<1; } } } void TestBlit(){ int buf[132]; int w = LCDWidth(); int h = LCDHeight(); for (int i = 0; i < w; i++) buf[i] = 0xF800; LCDSetBounds(0,0,w,h); for (int y = 0; y < h; y++) LCDBlit((const u8*)buf,w); } void TestBlit2(){ int buf[132]; int w = LCDWidth(); int h = LCDHeight(); for (int i = 0; i < w; i++) buf[i] = 0x001F; LCDSetBounds(0,0,w,h); for (int y = 0; y < h; y++) LCDBlit((const u8*)buf,w); } void TestIndexedBlit(){ int palette[132]; u8 indx[132]; int w = LCDWidth(); int h = LCDHeight(); for (int i = 0; i < w; i++){ palette[i] = 0xF800 + (i >> 2); indx[i] = i; } LCDSetBounds(0,0,w,h); for (int y = 0; y < h; y++) LCDBlitIndexed(( u8*)indx,(u8*)palette,w); } void TestFill(){ int cx = xor16() % LCDWidth(); int cy = xor16() % LCDHeight(); int radius = xor16() % LCDWidth(); Circle(cx,cy,radius>>2,xor16()); } void loop(){ LCDBegin(); time = millis(); for (int y = 0; y < 50; y++){ TestBlit(); TestBlit2(); } time2= millis()-time; Serial.print(time2); Serial.print(" "); Serial.print((10000000/time2)/100); Serial.print(","); Serial.println((10000000/time2)%100); }Посмотрел немного...есть указатели, но по другому передать массив в функцию в С и нельзя. Например строка 145 в срр, тут два указателя на начало массивов байт, и отдельно их размер. Код в функции просто передвигает указатель чтобы читать данные, понятно, что это работает быстро, потому что действительно никакие данные в другой массив не копируются, работа идет с исходным массивом.
...для примера, выражение *data++ это данные из ячейки с адресом data, после чтения адрес сдвигается на одну ячейку (в нашем случае байт, т.к data объявлен как указатель на u8)
так массив в си и есть указатель.
Что я говорил, то в исходниках и есть. Непрерывная область передается указателем, одно число (8-16 бит) передается по значению.
я бы успокоился, но нашел библиотеку которая делает почти 18 кадров/сек
....
так как я с ними не умею работать, и чтение различной литературы особо ясности не добавило, прощу объяснить как сделать максимальное быстродействие
Я тут тоже игрался с SPI но совсем с другой стороны... SPI далеко не медленная штука :-)
В вашей ситуации могу сказать что скорее всего ваша проблема в том, что вызов функции это не толко джамп и ретурн, но еше и перераспределение регистров и запись на стек. Компилятор такая "странная" штука что при работе со стеком и регистрами ориентируется на оптимизацию каждой конкретной функции а не общей производительности.
Короче говоря если чистое время посылки Х а время на вызров функции Y, то общее время ( X + Y ) * N.
Если же передавать массив то формула почти не измениться ( X + Z ) * N, где Z это время на цикл прохода по массиву. Причем в зависимости от платформы и компилятора Z минимум в 3-4 а то и в 10-20 раз меньше чем Y. Улавливаете разнцицу ? но что еще более интересно что моя чуйка мне говорит, что X и Z это значения одного порядка, если у вас hardware SPI.....
Если вы перепишите свой код на использования inline а компилятор сможет это выполнить, вы сразу поймете в чем смысл жизни. Правда за inline приходится платить размером конечной программы, она растет как на дрожжах
kisoft как вы считаете реально ли происходит ускорение если сделать например как в этой библиотеке. создаем массив на строку и его указателями отправляем
gregoryl не понял что вы хотите сказать
кстати пока без использования указателей поднял частоту с 3,37 кадра/сек до 9,64 кадра/сек
дальше хочу ногодрыгать через прямое управление портов
не
а
что будет быстрее. но писать тяжело если честно. пока не заработало
__Alexander не знаешь лучше молчи. тебе код дать где это работает?
Спешл во ю. Вот я подключил к хмеге, где spi 16Мгц. Давай, затыкай мне рот.
Или с математикой плохо? Давай считать, по SPI на 16Мгц ардине (это 8 реальных) ты один байт + одно ногодрыгание передашь за 3 мксек. Итого 128*160*2(байта на цвет)*3мксек = 123 мсек. т.е за секунду можно выплюнуть 8 кадров. хоть с указателями, хоть с папой римским. это тупо максимум.
http://youtu.be/yJ9z7VrpfPQ
интересно. у меня сейчас без указателей частота обновления экрана 9,64кадра/сек. что я делаю неправильно?))) ведь это больше чем максимальные 8 кадров в сек
я же примерно прикинул. давайте точнее посчитаем.
скорость зависит от этого куска, правильно?
void SpiData(u8 d){
MOSI1;
SCK1;
SCK0;
SPI_HW_ON;
SPDR = d;
SPI_HW_WAIT;
SPI_HW_OFF;
}
чтобы быть более точным, то прогнал в симуляторе. итого 2.5 мксек вместе в вызовом и возвратом. чтобы вывести 40960 быйт надо 102 400 мксек, что составляет 9.8 кадра. Но никак не 18, согласитесь.
И еще не забывайте что это просто заливка двумя байтами, если надо картинку выводить, то ее надо откуда-то брать, а это уже скорость напополам смело можно делить.
да но ведь разговор идет о просто заливке. если это ускорить то ускорится весь вывод
вот я и спрашиваю как это удалось в той библиотеке. код выложил чтобы понять как это получилось. там все сделано на указателях, и так как без них пока больше не получается ускорить, сделал вывод что дело наверно в них
Уважаемый "jeka_tm" взял ваш пример с бибилеотеками, подключил экранчик nokia 1616 (MOSI 11, SCK 13, CS 10, reset 8) но нечего не происходит (только горит подсветка), подскажите что сделал не так.
P.S. подключал к ардуино мини про
вот рабочий вариант на хардварном SPI
http://yadi.sk/d/CXjuENmaEEwun
файл называется Nokia_1616_HARD
распакуйте в папку с вашими скетчами
reset подключить к 3.3В
Огромное спасибо "jeka_tm".
Теперь встал вопрос: как вывести графику- картинку и чем конвертировить, желательно примерчик, я только пятаюсь всё понять (я новичок в этом деле).
с sd карточки я не пробовал еще, а из флеша без проблемм
вот только памяти сжирает очень много
2байта на цвет*128ширина*160высота= 40960 байт. картинку для всего экрана даже в обычную ардуину не засунешь
нужно цеплять sd карточку. я планирую сделать, как только разберусь с форматом bmp или научусь пользовать функциями библиотеки sd, там уже вроде все реализовано
я конвертирую lcd-image-converter
про sd читал думаю проблем не возникнет. а вот про дисплее не совсем понятно, вроде по теории всо нормально а как применить не знаю, прошу помочь на примере вашего кода и вот этой картинки.
Картинка 16bit (R5G6B5) 16x16:
Вот к примеру что содержится в каждом блоке "0xffff", цвет ? Как эту информицию обработать.
Заранее спасибо.
в инициализации дисплея включен режим 16 бит. вот ваши каждые 2 байта это 1 пиксель
в коде есть функция создания области вывода LCD_Window
создаете область вывода с вашими размерами рисунка
а потом просто цикл и считываете поочередно все байты из массива и рисуете пиксель
только пиксель рисуете не командой LCD_Pixel, а просто передаете данные командой
lcd_write16(color); где color цвет пикселя. чтение из массива слева направо сверху вниз
с командой lcd_write16 будет быстрее немного
можно и LCD_Pixel использовать, но тогда каждой точке надо задавать координаты
а если точки идут подряд можно просто передавать цвет
ffff это цвет. в данном случае белый
т.е. как я понимаю в даном случае это двухмерный масив цветов 16х16 ?
е ещё вопрос как обьявить этот масив как int или byte, просто как я понимаю в тип byte не влезить цвет за раз а в int влезит.
и как правельно передавать значение функции допустем так ?:
int myimg[] PROGMEM = {0xffff, 0xffff, 0xffdf, 0xf79e, 0xf79e, 0xf79e, .......... , 0xf79e, 0xf79e, 0xffdf, 0xffff, 0xffff} void LCD_drawImage (byte x, byte y, byte w, byte h, const int *bitmap) { for (byte _y=0; _y < h-1; _y++) { LCD_Window(x, y+_y, w, y+_y); for (byte _x=0; _x < w-1; _x++) { lcd_write16(bitmap[(_y*h)+_x]); } } void loop() { LCD_drawImage(25,25,16,16, myimg); delay(10000); }Кстати а как изменить контрастность ?
И ещё вопрос посмотрел откоректированную вами библеотеку "Adafruit_ST7735" она очень похожа на тот код что вы дали (фрагментами), возможно ли её легко-быстро переделать под дисплей 1616 или есть подводные камни ?
unsigned int
что то вроде
контрастность особо не удалось изменить, а вам зачем? вроде хорошо работает дисплей
хотя можете даташит покурить на контроллер дисплея
конечно они похожи. ведь и там и там дисплей с 16 битным режимом цвета, размер дисплея, и почти одинаковый интерфейс
зачем переделывать? вообще можно, но я не хочу, в чем смысл если получится почти тоже самое что я дал вам
контрастность особо не удалось изменить, а вам зачем? вроде хорошо работает дисплей
у меня получается если смотреть на него от шлейфа в верх то нехрена не видно, а наоборот сильно перенасыщенно.
конечно они похожи. ведь и там и там дисплей с 16 битным режимом цвета, размер дисплея, и почти одинаковый интерфейс
зачем переделывать? вообще можно, но я не хочу, в чем смысл если получится почти тоже самое что я дал вам
просто там всё структурировано плюс уже готовые примеры есть и их не надо переделовать )))
P.S. нашёл ошибку (или я чегото не правельно делаю) но если перевернуть экран (90 градусов) то получаем по недействующему пикселю по X и Y. вышей из ситуации так:
сделал переменую: byte lcd_mode =0;
и изменил "LCD_Window":
void LCD_Window(byte x, byte y, byte w, byte h) { lcd_write_cmd(0x2A); //x-координата if ((lcd_mode == 0) or (lcd_mode == 2)) {lcd_write16(x+2); lcd_write16(x+w+1);} else if ((lcd_mode == 1) or (lcd_mode == 3)) {lcd_write16(x+1); lcd_write16(x+w);} lcd_write_cmd(0x2B);//Y-координата if ((lcd_mode == 0) or (lcd_mode == 2)) {lcd_write16(y+1); lcd_write16(y+h+1);} else if ((lcd_mode == 1) or (lcd_mode == 3)) {lcd_write16(y+2); lcd_write16(y+h+2);} lcd_write_cmd(0x2C); }интересно ваше мнение, я ошибаюсь или всё верно ?
насчет контрастности я такого не замечал, смотрел на дисплей первендикулярно в основном
да и изменение контрастности что даст? с одной приведете например в норму, с другой вообще фиг знает что получите. я бы оставил как есть. это вам не ips чтобы углы обзора были хорошие. если так важны углы обзора меняйте дисплей
так переделайте либу и радуйтесь. если не можете тут я вам не помогу. рабочую уже дал
структурируйте эту если что то не устраивает
насчет пикселей надо потестить. я вроде тоже такое замечал, потом как нибудь поправлю
а насчет изменений тестируйте. только or не оставляйте
а насчет изменений тестируйте. только or не оставляйте
Очень интересует почему нельза OR ? и вместо него поставить || ?
Спасибо большое за помощь вы очень сильно помогли, теперь буду подключать sd и работать с bmp (я как понял в нём изображение с заду на перед читать надо).
да пожалуйста
||
насчет bmp я пока не разобрался. если разберетесь киньте код
а зачем голый бмп заливать, если его можно подготовить в читабельный вид перед сбросом на карту.
я делал вот так. на делфи.
Думаю в наш век проблем с размером sd карты не возникнет, а bmp читать то легко, это просто таблица пиксель-RGB, мне просто удобно видеть наглядно когда я подготовливаю флешку на пк.
http://en.wikipedia.org/wiki/BMP_file_format
У меня вот проблема возникла с подключением LCD и SD одновременно, если есть какие нибудь примерчики или разьяснения (желательно подробней) буду очень рад.
читать bmp то легко, только преобразование в 5-6-5 будет забирать время. т.е. следовательно - падение fps.
но я впринцепе фильмы гонять не буду поэтому мне хватит заглаза.
есть программка Easy Graphic Converter
конвертирует в 16 битный формат. на форуме находил инфу что в 5-6-5. но не уверен
попробовал конвертировать. работает. но что там получается хз
Помогите запустить LCD и SD одновремено, всё кроме CS подключено паралельно. По отдельности всё работает.
#include <avr/pgmspace.h> #include <SD.h> #include "Arduino.h" #include "fonts.h" #include "images.h" // ==================================================================================================================================================================== #define PIN_LCD 10 #define PIN_SD 4 #define CS 10 #define DAT 11 #define CLK 13 #define SPI_OFF SPCR = 0; #define SPI_ON SPCR = _BV(MSTR) | _BV(SPE); #define SPI_WAIT while (!(SPSR & _BV(SPIF))); // определение основных цветов 16bit #define BLACK 0x0000 #define WHITE 0xffff #define RED 0xF800 #define GREEN 0x07E0 #define BLUE 0x001F #define YELLOW 0xFFE0 //Желтый #define CYAN 0x07FF //Голубой #define MAGENTA 0xDEE0 //Фиолетовый //#define DISP_W 128 //#define DISP_H 160 byte DISP_W = 128; byte DISP_H = 160; byte lcd_mode =0; #define CHAR_W 8 #define CHAR_H 15 #define CS_On PORTB = 1<<2 // CS PB2 #define CS_Off PORTB = 0<<2 #define DAT_On PORTB = 1<<3 // Data PB3 #define DAT_Off PORTB = 0<<3 #define CLK_On PORTB = 1<<5 // Clock PB5 #define CLK_Off PORTB = 0<<5 unsigned int bgcolor = BLACK; //=============================Вывод на дисплей 8 бит комманд=================================== void lcd_write_cmd(byte c){ SPI_WAIT; SPI_OFF; DAT_Off; CLK_On; CLK_Off; SPI_ON; SPDR = c; } //=============================Вывод на дисплей 8 бит данных==================================== void lcd_write_dat(byte c){ SPI_WAIT; SPI_OFF; DAT_On; CLK_On; CLK_Off; SPI_ON; SPDR = c; } //============================Вывод на дисплей 16 бит данных==================================== void lcd_write16(unsigned int dat){ lcd_write_dat(dat>>8); lcd_write_dat(dat); } //================================Инициализация дисплея========================================= void lcd_init_rgb(byte mode = 0){ pinMode(CS, OUTPUT); pinMode(DAT, OUTPUT); pinMode(CLK, OUTPUT); SPSR |= 8; // 2x clock SPI_ON; SPDR = 0x00; CS_Off; delay(10); CS_On; lcd_write_cmd(0x01); delay(50); //reset CS_Off; lcd_write_cmd(0xBA); // Порядок отсылки данных lcd_write_dat(0x07); lcd_write_dat(0x15); lcd_write_cmd(0x25); // Контраст lcd_write_dat(0x3F); lcd_write_cmd(0x11); // Выход из режима sleep, (0x10) sleep lcd_write_cmd(0x14); lcd_write_cmd(0x37); // Дополнительные настройки lcd_write_dat(0x00); lcd_write_cmd(0x3A); lcd_write_dat(0x05); lcd_write_cmd(0x29); // Включить дисплей, (0x28) выключить lcd_write_cmd(0x20); // Нормальный режим, (0x21) инвертированный lcd_write_cmd(0x36); // Ориентация дисплея lcd_mode = mode; if (mode == 0){ lcd_write_dat(0xC0); // 0 градусов DISP_W = 128; DISP_H = 160; } if (mode == 1){ lcd_write_dat(0xA0); // 90 градусов DISP_W = 160; DISP_H = 128; } if (mode == 2){ lcd_write_dat(0x00); // 180 градусов DISP_W = 128; DISP_H = 160; } if (mode == 3){ lcd_write_dat(0x60); // 270 градусов DISP_W = 160; DISP_H = 128; } lcd_write_cmd(0x13); CS_Off; } //===================================Заливка дисплея============================================ void LCD_Fill_all(unsigned int color){ LCD_Window(0, 0, DISP_W, DISP_H); byte i=DISP_H; byte j; while(i--){ j=DISP_W; while(j--){ lcd_write16((color)); } } } //================================Переход в координаты XY======================================= void LCD_XY(byte x, byte y){ lcd_write_cmd(0x2A); //x-координата lcd_write16(x+2); lcd_write_cmd(0x2B);//Y-координата lcd_write16(y+1); } //============================Создание области для рисования==================================== void LCD_Window(byte x, byte y, byte w, byte h){ lcd_write_cmd(0x2A); //x-координата //lcd_write16(x+2); if ((lcd_mode == 0) or (lcd_mode == 2)) {lcd_write16(x+2); lcd_write16(x+w+1);} else if ((lcd_mode == 1) or (lcd_mode == 3)) {lcd_write16(x+1); lcd_write16(x+w);} //lcd_write16(x+w+1); lcd_write_cmd(0x2B);//Y-координата //lcd_write16(y+1); if ((lcd_mode == 0) or (lcd_mode == 2)) {lcd_write16(y+1); lcd_write16(y+h+1);} else if ((lcd_mode == 1) or (lcd_mode == 3)) {lcd_write16(y+2); lcd_write16(y+h+2);} //lcd_write16(y+h+1); lcd_write_cmd(0x2C); } //====================================Рисуем пиксель============================================ void LCD_Pixel(byte x, byte y, int color){ LCD_XY(x,y); lcd_write_cmd(0x2C);// WR_MEM lcd_write16(color); } //===========================Вывод символа в XY заданного цвета================================= void LCD_Char(byte x, byte y, unsigned char c, unsigned int color){ byte ch; byte mask = 0x80; LCD_Window(x, y, CHAR_W, CHAR_H); for (byte h=0; h<CHAR_H; h++){ // every column of the character ch=pgm_read_byte(&(FONT8x15[c-32][h])); mask = 0x80; for (byte p=0; p<CHAR_W; p++){ // write the pixels (ch & mask)? lcd_write16(color) : lcd_write16(bgcolor); mask >>= 1; } } } //===========================Вывод текста в XY заданного цвета================================== void put_string(byte x, byte y, char *str, unsigned int color){ unsigned char j; j=0; while (j<strlen(str)){ LCD_Char((x+j*CHAR_W),y,str[j], color); j++; } } //===================================Линия======================================= void LCD_Line(byte x0, byte y0, byte x1, byte y1, unsigned int color){ int dy = y1 - y0; int dx = x1 - x0; int stepx, stepy; if (dy < 0){ dy = -dy; stepy = -1; } else stepy = 1; if (dx < 0){ dx = -dx; stepx = -1; } else stepx = 1; dy <<= 1; // dy is now 2*dy dx <<= 1; // dx is now 2*dx LCD_Pixel(x0, y0, color); if (dx > dy) { int fraction = dy - (dx >> 1); // same as 2*dy - dx while (x0 != x1){ if (fraction >= 0) { y0 += stepy; fraction -= dx; // same as fraction -= 2*dx } x0 += stepx; fraction += dy; // same as fraction -= 2*dy LCD_Pixel(x0, y0, color); } } else{ int fraction = dx - (dy >> 1); while (y0 != y1){ if (fraction >= 0){ x0 += stepx; fraction -= dy; } y0 += stepy; fraction += dx; LCD_Pixel(x0, y0, color); } } } //==========================================Круг=============================================== void LCD_Circle(byte x0, byte y0, byte r, unsigned int color) { int16_t f = 1 - r; int16_t ddF_x = 1; int16_t ddF_y = -2 * r; int16_t x = 0; int16_t y = r; LCD_Pixel(x0 , y0+r, color); LCD_Pixel(x0 , y0-r, color); LCD_Pixel(x0+r, y0 , color); LCD_Pixel(x0-r, y0 , color); while (x<y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; LCD_Pixel(x0 + x, y0 + y, color); LCD_Pixel(x0 - x, y0 + y, color); LCD_Pixel(x0 + x, y0 - y, color); LCD_Pixel(x0 - x, y0 - y, color); LCD_Pixel(x0 + y, y0 + x, color); LCD_Pixel(x0 - y, y0 + x, color); LCD_Pixel(x0 + y, y0 - x, color); LCD_Pixel(x0 - y, y0 - x, color); } } void LCD_VLine(byte x, byte y, byte h, unsigned int color) { LCD_Line(x, y, x, y+h-1, color); } void LCD_HLine(byte x, byte y, byte w, unsigned int color) { LCD_Line(x, y, x+w-1, y, color); } void LCD_Rect(byte x, byte y, byte w, byte h, unsigned int color) { LCD_HLine(x, y, w, color); LCD_HLine(x, y+h-1, w, color); LCD_VLine(x, y, h, color); LCD_VLine(x+w-1, y, h, color); } void LCD_drawBitmap(byte x, byte y, const byte *bitmap, byte w, byte h, unsigned int color){ byte i, j, byteWidth = (w + 7) / 8; for(j=0; j<h; j++) { for(i=0; i<w; i++ ) { if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) { LCD_Pixel(x+i, y+j, color); } } } } void LCD_drawImage (byte x, byte y, byte w, byte h, const int *bitmap) { for (byte _y=0; _y < h-1; _y++) { LCD_Window(x, y+_y, w, y+_y); for (byte _x=0; _x < w-1; _x++) { lcd_write16(bitmap[(_y*h)+_x]); } } } uint16_t ConvertColorRGB(uint8_t r, uint8_t g, uint8_t b) { //565 return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } /*void LCD_Off (){ digitalWrite(CS, LOW); pinMode(CS, INPUT); delay(80); pinMode(CS, INPUT); } void LCD_On () { pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); digitalWrite(CS, LOW); }*/ // ==================================================================================================================================================================== void setup(){ Serial.begin(9600); lcd_init_rgb(1); /* if (!SD.begin(PIN_SD)) { Serial.println("Card failed, or not present"); // don't do anything more: return; } Serial.println("card initialized.");*/ //pinMode(PIN_SD, OUTPUT); //pinMode(PIN_SD, OUTPUT); /*pinMode(2, OUTPUT); digitalWrite(2, HIGH);*/ LCD_Fill_all(bgcolor); //LCD_Fill_all(ConvertColorRGB(255,255,255)); //put_string(20, 20, "privet", RED); //LCDInit(); } //u16 xor16(void); void loop(){ //LCDBegin(); //LCD_On; //for (int y = 0; y < 50; y++){ LCD_Fill_all(BLACK); put_string(20, 20, "privet", RED); delay(3000); LCD_Fill_all(GREEN); delay(1000); LCD_Fill_all(BLUE); delay(1000); File dataFile = SD.open("ico.txt"); // if the file is available, write to it: if (dataFile) { while (dataFile.available()) { Serial.write(dataFile.read()); } dataFile.close(); } // if the file isn't open, pop up an error: else { Serial.println("error opening datalog.txt"); } LCD_Fill_all(RED); delay(1000); LCD_Fill_all(ConvertColorRGB(255,255,255)); delay(5000); /*LCD_drawImage(0,0,16,16, myimgq2); LCD_drawImage(0,112,16,16, myimgq2); LCD_drawImage(25,25,16,16, myimgq2); LCD_drawImage(50,25,16,16, myimgq2); LCD_drawImage(25,50,16,16, myimgq2); LCD_drawImage(25,75,16,16, myimgq2); LCD_drawImage(50,75,16,16, myimgq2);*/ //LCD_drawBitmap(1,1, myimg,96,68, GREEN); //byte zz; //for (zz = 1; zz < 256; zz++){ // LCD_Fill_all(myimgq[zz]); // Serial.print("Num: "); // Serial.print(zz); // Serial.print(" Data: "); // Serial.println(myimgq[zz]); // delay(1500); //} //TestBlit(); //delay(3000); //TestBlit2(); // delay(3000); // TestIndexedBlit(); // delay(3000); // TestFill(); // delay(3000); // } }Ну что никто не знает как переключатся между LCD и SD ?
этот код я делал чтобы выжать макс скорость отрисовки экрана, и для работы с sd и дисплеем не особо подходит. точнее подходит, но нужно один кусок поправить. точнее функцию lcd_write_cmd и lcd_write_dat
изменения одинаковые
а переключаться просто (наверно, я только теоретически догадываюсь). есть пинь SS вроде называется (обычно), короче выбор нужного устройства на SPI выбирая этот пин. и перидически переключаться между дисплеем и карточкой.
как именно это сделать думаю помогут более знающие люди. лешак может поможет, в программировании гораздо сильнее меня. я так начинающий
интересует как работать с файлом картинки сохраненной на SD. допустим один файл одна картинка. формат bmp. возможно уже сконвертированный в формат R5G6B5 (если программа конвертирует как надо)
интересует следующее. так как всю картинку считать оперативки не хватит, нужно по кускам. как это делает? скорее всего считывается например 500 байт а потом выводятся на дисплей и так далее пока не считается вся картинка
вопрос как считывать картинку с SD и как считывать по кускам файл
>вопрос как считывать картинку с SD
Вы одновременно работы SD и экрана уже добились?
нет. я к sd даже не приступал. точнее только считывал только инфу что карточке, и свобоное место
вот думаю как подступится
библиотека конечно есть, но что делать хз. код то готовый был
нет. я к sd даже не приступал. точнее только считывал только инфу что карточке, и свобоное место
Так вот это "считывал инфу на карточке" одноврменно с экраном или нет?
нет. вывод был через w5100 насколько помню
экран я отдельно запускал
нет. вывод был через w5100 насколько помню
экран я отдельно запускал
нет. вывод был через w5100 насколько помню
Ну в теории тут должно быть то же самое. Причем теорию вы сами озвучили выше :) Каждому свой SS пин и перед тем как работать с кем-то из них - включать его, а после - выключать.
Вначале добейтесь тупого:
1. Проинициализировать экран, и вывести на него, скажем цифру один.
2. Отклчить его SS
3. Проинициализировать SD (включив ее SS), что-нибудь с нее прочитать (ту же инфу) и отправить в Serial
4. Выключить SS sd-шки.
5. Включить SS экрана, вывести на него цифру два.
Ну вообщем если эти пункты удайтся пройти то можно сказать "они работают одновременно". Потом можно будет разбиратся как "читать по кускам" и т.п.
В качестве примера можно как раз про w5100 смотреть, там тоже "по очереди" с ними работают.
1. я уже сделал. библиотеку писал же, помогли конечно. но основное я. я туда и FFT выводил уже
2. это могу
3-5 попробую завтра
Так, шо-бы було... когда дойдете до bmp-шки читать, вот такая ссылочка нагуглилась: https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/blob/master/examples/bmp/bmp.pde там можно попытатся спионерить чтение, парсинг bmp-шки.
Только уже вывод самой точки на экран, на вызов вашей библиотеки подменить.
о спасибо. завтра будут пробывать. че то я железе зарылся в последнее время
ирония судьбы)))
о спасибо. завтра будут пробывать. че то я железе зарылся в последнее время
Не, не.... до этого еще далеко. У нас еще куча всего проверить будет... маленькими шагами. Только так.
Сделать 5 копипастов из 5-ти мест получить портянку на 15 пейждаунов, а потом пытаться разобраться "что же тут не так" - это не наш метод (ну по крайней мере такое - без меня).
а вам значит можно, а мне нельзя. так нечестно
а вам значит можно, а мне нельзя. так нечестно
Кто сказал что "мне можно"? Я ссылочку оставил что-бы "не потерялась" :)
А сам я тоже, только вначале по частям все проверить, потом начать добавлять по ОДНОЙ фишке.
Только малыми шагами, только так, только одно что-то за раз меняя.
Я вот сам бы ровно по тем же шагам что вам перечислил делал бы. Я вот с новым железом (с програмно части) тоже разбираюсь именно так.
Я ведь не имею вашего экрана... но вообщем-то не первый раз уже через форум разбирается-запускаем, именно пошагово, с железом которое никогда в руках не держал и не видел.
да я так, не спорю. сам бы так сделал. все собирался занятся этим вопросом. все откладывал
но с вашей поддержкой будет проще. не хватает знаний