Ср ноя 25, 2015 15:41:07
Ср ноя 25, 2015 18:33:28
Чт ноя 26, 2015 14:16:19
Сб апр 16, 2016 14:35:03
WiseLord писал(а):Ну.. не знаю. По даташиту ширина строба (Tpw) при чтении 320нс. Об остальном заботится процедура чтения флага занятости.
Ну а dummy read - да, нужен. У меня тоже использовалось (опечатка в комментарии).
- Код:
static uint8_t st7920ReadData()
{
uint8_t data;
st7920WaitWhile(ST7920_STATUS_BUSY);
ST7920_CTRL_PORT |= ST7920_RS;
data = st7920Strob();
return data;
}
Сб апр 16, 2016 16:46:23
Сб апр 16, 2016 21:31:19
uint8_t ABC[16],
a;
Set_Adress(0,0);
RS=1:
RW=1;
Strob();
for(a=0; a<16; a++)
{
Strob();
ABC[a] = PORTC;
}
RW=0;
Set_Adress(20,0);
for(a=0; a<16; a++)
{
PORTC = ABC[a];
Strob();
}
Сб апр 16, 2016 21:51:06
- Код:
if (data & (128>>k))
fb[j * 8 + k] |= (1<<i);
else
fb[j * 8 + k] &= ~(1<<i);
Вс апр 17, 2016 01:50:23
Раз. Два. Три.Burgunsky писал(а):Мене просто удивило, что Вы принудительно RW в единицу не загоняете
Это другое, просто поворот на 90 градусов. У KS0108, изначально использовавшемся мною, данные, посылаемые в дисплей, отображаются на нём в виде вертикальных столбиков, а у ST7920 - горизонтально. Поэтому такой кусок кода фактически поворачивает на 90 градусов данные. То есть, сначала данные (строка, например) пишутся в буфер fb размером 128 байт (128 вертикальных столбиков), после чего, для посылки в ST7920, этот буфер пересчитывается в горизонтальные байты.Burgunsky писал(а):Если Вас не затруднит, проясните сакральный смысл этого чудо-алгоритма
Достаточно и 50мкс, на самом деле.Burgunsky писал(а):Пробовал выставлять задержку 100мкСек тупо после каждой команды. Результат идентичный
Навскидку, я не вижу переключения порта C с выхода на вход при попытке чтения. Поэтому непонятно, что именно вычитывается в буфер ABC, но точно не данные, которые выдаёт дисплей. Скорее, какое-то их наложение на то, что выдаёт сам МК на выход. И вопрос, кто кого "передавит" - выходные транзисторы МК или дисплея.Burgunsky писал(а):Подскажите, пожалуйста что не так в алгориртме ниже.
Пн апр 18, 2016 17:17:40
WiseLord писал(а):Навскидку, я не вижу переключения порта C с выхода на вход при попытке чтения.
WiseLord писал(а):Раз. Два. Три.
Пн апр 18, 2016 17:56:48
Вт апр 19, 2016 16:04:49
WiseLord писал(а):ST7920_CTRL_PORT |= ST7920_PSB устанавливает один бит порта, не затрагивая остальные
Если контроллер позволяет (имеет от 2кБ ОЗУ)
Таймер вызывает раз в 50мкс прерывание,
Вт апр 19, 2016 17:23:52
Burgunsky писал(а):Я обычно в таких случаях битовые поля использую
typedef struct {
bit0:1; bit1:1; bit2:1; bit3:1; bit4:1; bit5:1; bit6:1; bit7:1;
} myVar;
myVar var;
var.bit1 = 0;
var.bit2 = 1;
Те же ATmega328, ATmega32 достаточно популярны.Burgunsky писал(а):Ни разу не работал с такими крутыми. Это не фантастика?
Вт апр 19, 2016 19:58:53
typedef union {
struct {
unsigned RA0 :1;
unsigned RA1 :1;
unsigned RA2 :1;
unsigned RA3 :1;
unsigned RA4 :1;
unsigned RA5 :1;
unsigned RA6 :1;
unsigned RA7 :1;
};
} PORTAbits_t;
extern volatile PORTAbits_t PORTAbits @ 0x005;
Пт июн 24, 2016 18:41:11
Ср июн 29, 2016 11:14:39
Я тоже по даташиту не въехал, потом как то где то подсмотрел и чтото получилось... со временем накидал свою библиотечку...afz писал(а):Что-то не въеду, как с этим дисплеем работать в Serial Mode.
//#######################################################################################################################
//#
//# БИБЛИОТЕКА РАБОТЫ С ГРАФИЧЕСКИМИ ДИСПЛЕЯМИ ----- SERIAL ST7920
//#
//#######################################################################################################################
///дефайны портов дисплея ST7920
#define LCD_PORT PORTD
#define LCD_DDR DDRD
#define LCD_CS_LINE (1<<0)
#define LCD_DATA_LINE (1<<1)
#define LCD_CLK_LINE (1<<2)
//константы
#define CMND 0
#define DATA 1
#define LCD_H_SIZE 16 /*размер экрана в символах по горизонтали*/
#define LCD_V_SIZE 8 /*размер экрана в символах по вертикали*/
//Глобальные переменные
uint8_t SymbBuf [LCD_H_SIZE][LCD_V_SIZE]; //виртуальный текстовый буфер
uint8_t SBufPosX; //позиция для печати по горизонтали в виртуальном символьном буфере
uint8_t SBufPosY; //позиция для печати по вертикали в виртуальном символьном буфере
uint8_t SBufBigSimbMask; //флаговая маска строк с увеличенным шрифтом
//#######################################################################################################################
//#
//# ДРАЙВЕР ДИСПЛЕЯ ST7920
//#
//#######################################################################################################################
//Объявления
void LcdSerialBitOut (uint8_t bit);
void LcdSerialByteOut (uint8_t byte, uint8_t type);
//----------
//Инициализация графического режима.
void LcdInit (void)
{
LCD_DDR |= LCD_CLK_LINE | LCD_DATA_LINE | LCD_CS_LINE;
_delay_ms (1);
LcdSerialByteOut (0x30, CMND); //8 бит, стандартный набор комманд.
_delay_ms (1);
LcdSerialByteOut (0x36, CMND); //Включить дисплей.
_delay_ms (1);
LcdSerialByteOut (0x01, CMND); //Режим пониженного энергопотребления.
}
//----------
//Очистка графического дисплея.
void LcdClear (void)
{
for (uint8_t line = 0; line<32; line++){
LcdSerialByteOut(0x80|line, CMND); //Ставим указатель в начало строки 0..31.
LcdSerialByteOut(0x80, CMND);
for (uint8_t clmn = 0; clmn<32; clmn++){ //В каждой строке затираем 32 байта.
LcdSerialByteOut(0, DATA);
}
}
}
//----------
//вывод байта команды\данных на дисплей
//АРГУМЕНТ1 - байт данных
//АРГУМЕНТ2 - тип данных, (0-команда, 1-данные)
void LcdSerialByteOut (uint8_t byte, uint8_t type)
{
LCD_PORT |= LCD_CS_LINE; //начало работы
for (uint8_t i=0; i<5; i++) //5 единиц
LcdSerialBitOut (1);
LcdSerialBitOut (0); //0-запись, 1-чтение
LcdSerialBitOut (type); //0-команда, 1-данные
LcdSerialBitOut (0);
for (uint8_t x=0; x<2; x++){
for (uint8_t i=0; i<4; i++){ //передаем 4 старших потом 4 младших бита данных
if (byte & 0x80) LcdSerialBitOut (1);
else LcdSerialBitOut (0);
byte <<= 1;
}
for (uint8_t i=0; i<4; i++) //4 нуля
LcdSerialBitOut (0);
}
asm ("nop");
asm ("nop");
LCD_PORT &= ~(LCD_DATA_LINE | LCD_CS_LINE); //сброс линии данных и конец связи
}
//----------
//вывод бита данных на дисплей
//АРГУМЕНТ - бит данных 0 или 1
void LcdSerialBitOut (uint8_t bit)
{
if (bit) LCD_PORT |= LCD_DATA_LINE;
else LCD_PORT &= ~LCD_DATA_LINE;
asm ("nop");
asm ("nop");
LCD_PORT |= LCD_CLK_LINE;
asm ("nop");
asm ("nop");
LCD_PORT &= ~LCD_CLK_LINE;
}
//----------
//Вывод данных из виртуального текстового буфера в графический LCD
void SBufToLcd (void)
{
//перебор 8-ми текстовых строк
for (uint8_t y=0; y<8; y++){
//обработка больших 16х16 символов
if (SBufBigSimbMask & (1<<(7-y))){
//цикл двух половинок увеличенного шрифта ВЕРХНЕЙ половины строки и НИЖНЕЙ половины
for (uint8_t part=0; part<2; part++){
//цикл вывода символов двойного размера (ВЕРХНЯЯ половина строки)
for (uint8_t ln = 0; ln<8; ln++){ //перебор горизонтальных линий в строке
LcdSerialByteOut(0x80+(((y+part)*8+ln)%32), CMND); //ставим указатель в начало линии
LcdSerialByteOut(0x80+((y+part)/4*8), CMND);
//перебор растянутых байтов в линии
for (uint8_t x = 0; x<8; x++){
uint8_t* pFont = (uint8_t*)Font8x8Table + ((SymbBuf [x][y] - 0x20) * 8);
uint8_t Byte = pgm_read_byte (pFont + (ln/2) + (part*4));
uint16_t Word = 0;
for (uint8_t i=0; i<8; i++)
if (Byte & (1<<i)) Word |= (0b11<<(i*2));
LcdSerialByteOut ((Word>>8), DATA);//вывод старшей части растянутого символа
LcdSerialByteOut (Word, DATA); //вывод младшей части растянутого символа
}
}
}
y++; //проскакиваем следующую строку
}
//обработка обычных 8х8 символов
else for (uint8_t ln = 0; ln<8; ln++){ //перебор горизонтальных линий в строке
LcdSerialByteOut(0x80+((y*8+ln)%32), CMND); //ставим указатель в начало линии
LcdSerialByteOut(0x80+(y/4*8), CMND);
for (uint8_t x = 0; x<16; x++){ //перебор байтов в линии
uint8_t symb = SymbBuf [x][y];
uint8_t* pFont = (uint8_t*)Font8x8Table + ((symb - 0x20) * 8);
LcdSerialByteOut (pgm_read_byte (pFont + ln), DATA);
}
}
}
}
//#######################################################################################################################
//#
//# функции работы с буфером
//#
//#######################################################################################################################
//установить указатель в виртуальном символьном буфере на нужное смещение
//АРГУМЕНT_1 - смещение по оси X - от 0 LCD_H_SIZE
//АРГУМЕНТ_2 - смещение по оси Y - от 0 LCD_V_SIZE
void SBufGotoXY (uint8_t x, uint8_t y)
{
if ((x >= LCD_H_SIZE) || (y >= LCD_V_SIZE))
return;
SBufPosX = x;
SBufPosY = y;
}
//----------
//очистка виртуального символьного буфера
void SBufClear (void)
{
for (uint8_t y=0; y<LCD_V_SIZE; y++)
for (uint8_t x=0; x<LCD_H_SIZE; x++)
SymbBuf [x][y] = 0x20;
SBufGotoXY (0,0);
}
//----------
//печать символа в виртуальный символьный буфер
//АРГУМЕНТ - код печатаемого символа
void SBufSimbPrint (uint8_t symbol)
{
SymbBuf [SBufPosX][SBufPosY] = symbol;
if (++SBufPosX >= LCD_H_SIZE){
SBufPosX = 0;
if (++SBufPosY >= LCD_V_SIZE)
SBufPosY = 0;
}
}
//----------
//печать текста из PROGMEM в виртуальный символьный буфер
//АРГУМЕНТ - указатель на строку в PROGMEM
void SBufStringPrintPgm (uint8_t* pString)
{
while (1){
char symb = pgm_read_byte (pString++);
if (! symb) return;
SBufSimbPrint (symb);
}
}
//----------
//печать страницы из PROGMEM в виртуальный символьный буфер
//АРГУМЕНТ - указатель на страницу в PROGMEM
void SBufPagePrintPgm (uint8_t* pString)
{
SBufClear ();
SBufGotoXY (0,0);
SBufStringPrintPgm (pString);
}
//----------
//печать строки в виртуальный символьный буфер
//АРГУМЕНТ - указатель на строку в RAM
void SBufStringPrintRam (char* pString)
{
while (1){
char symb = *pString++;
if (! symb) return;
SBufSimbPrint (symb);
}
}
//----------
//функция рисования рамки
//АРГУМЕНТ1 - начало рамки по X
//АРГУМЕНТ2 - начало рамки по Y
//АРГУМЕНТ3 - конец рамки по X
//АРГУМЕНТ4 - конец рамки по Y
void SBufFrame (uint8_t StrtX, uint8_t StrtY, uint8_t EndX, uint8_t EndY)
{
//некорректные данные
if ((StrtX >= EndX) || (StrtY >= EndY)) return;
if ((EndX >= LCD_H_SIZE) || (EndY >= LCD_V_SIZE)) return;
//углы рамки
SBufGotoXY (StrtX,StrtY); SBufSimbPrint (0xAA); //верх лево
SBufGotoXY (EndX,StrtY); SBufSimbPrint (0x87); //верх право
SBufGotoXY (StrtX,EndY); SBufSimbPrint (0xA4); //низ лево
SBufGotoXY (EndX,EndY); SBufSimbPrint (0x8C); //низ право
//верхняя горизонтальная линия
uint8_t temp = StrtX+1;
SBufGotoXY (temp,StrtY);
while (temp != EndX){
SBufSimbPrint (0x94);
temp++;
}
//нижняя горизонтальная линия
temp = StrtX+1;
SBufGotoXY (temp,EndY);
while (temp != EndX){
SBufSimbPrint (0x9D);
temp++;
}
//левая вертикальная линия
temp = StrtY+1;
while (temp != EndY){
SBufGotoXY (StrtX,temp++);
SBufSimbPrint (0x83);
}
//правая вертикальная линия
temp = StrtY+1;
while (temp != EndY){
SBufGotoXY (EndX,temp++);
SBufSimbPrint (0x8A);
}
}
//----------
//настройка строк двойного размера
void SBufBigSimbSet (uint8_t BigSimbMask)
{
SBufBigSimbMask = BigSimbMask;
}
//#######################################################################################################################
//#
//# THE END
//#
//#######################################################################################################################
Ср июн 29, 2016 18:12:51
А почему вручную, дрыгая ножками? Я так прикинул, по идее должно получиться использовать аппаратный SPI. Там же заявлено 72 мкс между соседними байтами, и, как кто-то утверждал здесь раньше, можно "разогнать" его до 32-33 мкс, при большем разгоне появляются артефакты. Учитывая посылку одного байта 24 битами, чтобы обеспечить их передачу за 72 мкс нужна частота SCLK 333.3 кГц, увеличив ее до 666.7 кГц можно разогнать дисплейчик до 36 мкс. Я так думаю, что разгон "до упора" не есть хорошо, поэтому можно взять Мегу с кварцем, допустим, 7372.8 кГц, запустить ее аппаратный SPI с делителем 16, при этом получим 460.8 кГц SCK (SCLK), разгон при этом будет 52 мкс, т.е. порядка 1.4, при этом SPI, получив очередной байт, будет самостоятельно его обрабатывать в течение 128 тактов; спокойно можно делать в прерываниях, без всяких ожиданий.Либка получилась достаточно компактная, помоему около 1-2 кило, даже на мега8 можно легко развернуться...
Ср июн 29, 2016 21:47:46
Наверное можно использовать и SPI, но меня устраивает и так... слишком уж много внимания и условий для решения по вашему варианту... тем более что на повышенных частотах некоторые дисплеи могут и не заработать...afz писал(а):А почему вручную, дрыгая ножками?
Чт июн 30, 2016 05:09:50
Тоже, конечно, вариант. Но я хочу попробовать обойтись без экранного буфера. Если подобрать изображения так, чтобы части, подлежащие изменениям, начинались по горизонтали с положения, кратного 16 точкам, то, вроде-бы, все должно получиться.Кроме того, обновление экрана происходит в основном цикле (не мешая прерываниям) в следующих ситуациях - изменение положения курсора, обновление данных, изменение контекста и т.д.... т.е. довольно редко...
Каких условий? Всего-то надо подобрать частоту SCK, то есть при заданной частоте кварца выбрать коэффициент деления, чтобы SCK оказалась в пределах 333-666 кГц. Ну да, еще ножки привязаны. Аж целых две. Нет, даже две с половиной.слишком уж много внимания и условий для решения по вашему варианту...
Чт июн 30, 2016 05:53:54
Чт июн 30, 2016 10:28:52
Тоже вариант, по идее должно получится...afz писал(а):хочу попробовать обойтись без экранного буфера.
Ну да... вроде так...WiseLord писал(а):- для передачи команды 0bABCDEFGH передаём по SPI 0b11111000 0bABCD0000 0bEFGH0000
- для передачи данных 0bABCDEFGH передаём по SPI 0b1111010 0bABCD0000 0bEFGH0000
Правильно ли я понял суть?
Пробовать надо... даже не помню, где и что по этому поводу говорилось... возможно что не нужно каждый раз дергать...WiseLord писал(а):И ещё, есть ли смысл по окончании передачи байта опускать CS, а по началу следующего - снова поднимать? Что будет, если держать его в 1 постоянно?
Да так...WiseLord писал(а):PSB (единица в параллельном мрежиме) = PSB (ноль в последовательном)
RS (данные/команда в параллельном режиме) = CS (chip select в последовательном)
E (строб в параллельном режиме) = SCLK (тактирование в последовательном)
RW (запись/чтение в параллельнмо режиме = SID (вход данных в последовательном)
Оставить как есть...WiseLord писал(а):И что делать с D0-D7, занулить или можно оставить как есть?