С stm32f103 на телевизор (полный TV сигнал)
- Войдите на сайт для отправки комментариев
Не то, чтобы я считаю эту тему актуальной, но ведь кому-то понадобилось делеть TV-выход на Nano даже при том, что там отображается всего 20 символов в строке...
Опять же, не прошло и месяца, как аналоговое телевидение вышло из моды. ))) А аналоговые телевизоры остались...
Ну и на Ардуино выбор экранов (с разрешением от 128 по горизнтали) обычно ограничивается двумя непересекающимися диапазонами:
- от менее дюйма до примерно 4 юймов,
- от 20-40 дюймов и больше.
А промежуточный диапазон перекрывают как раз аналоговые TV-приемники.
В общем, первые прикидки показали, что можно сделать на stm32 формирователь полного телевизионного сигнала с разрешением экрана 512х240 пикселей, что дает 64 символа в строке для символов 8х8 или 8х12, а также до 85 символов в строке для достаточно стандартного для Ардуино фонта 6х8 (5х7).
Первая попытка:
Здесь шахматное поле с клеткой 16х16, поверх которого нарисована одниписельная прямая из левого верхнего угла вправо вниз, а также надписи шрифтами 6х8, 8х12 (зернкально) и 8х8 (жирный).
Интересно, хотя и непонятно зачем :)
С интересом жду подробностей по реализации этого в коде.
О_О
Давно хотел реализовать на работу табло с текущими параметрами эксперимента на большом экране 40 дюймого телевизора притащенного аспирантами из дома за ненадобностью. Уже полгода лежит без дела. Присоединяюсь. Реализую в ближайшее время. Только шрифт будет большим, чтобы из далека было видно.
P.S. Они уже всё сделали :-(
https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/libraries/A_STM32_Examples/examples/Maple/CrudeVGA/CrudeVGA.ino
b707, я тоже не очень понимаю, зачем.
Ну, например, есть у меня Orange Zero. Непроверенный. Потому как без видеоконтроллера, но с TTL UART. Так что можно было бы использовать подобную конструкцию в качестве видеотерминала.
b707, я тоже не очень понимаю, зачем.
Ну, например, есть у меня Orange Zero. Непроверенный. Потому как без видеоконтроллера, но с TTL UART. Так что можно было бы использовать подобную конструкцию в качестве видеотерминала.
Очень напомнило:
Однажды Ходжу Насреддина спросили:
-- Как избавиться от крыс?
-- Очень просто! - сообщил Ходжа.
-- Нужно растолочь черепки в порошок и, когда поймаешь крысу, засыпать ей это порошок в ноздри. Крыса не сможет дышать и издохнет.
-- Но если я поймал крысу, не проще ли убить ее, ударив об стену?
-- Конечно проще! - ответил Ходжа.
P.S. Они уже всё сделали :-(
https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/libraries/A_STM32_Examples/examples/Maple/CrudeVGA/CrudeVGA.ino
Ну, этот исходник я, разумеется, изучил и даже кое-что из него замствовал.
То есть полезное там как бы есть, но использовать это на практике нельзя.
Похоже, выглядит это так:
1. Все это делается программно, причем, по горизонтали получается что-то чуть больше 20 "пикселов".
2. Есть один неприятный момент, который мне как раз хотелось бы обсудить.
Меня интересуют строки исходника 91 и 107. В первую очередь, конечно, 107, потому что 91, на мой взгляд, совершенно бесполезна.
Дело в том, что без этих строк (в том числе и у меня) на экране промелькивают помехи, а в результате Serial.end() эти помехи исчезают, но одновременно с этим "отваливается" USB порт. Т.е. перепрошить плату в дельнейшем удается только, нажав в нужный момент на RESET. Похоже, этот Serial.end() убивает как USB, так и милисекундные прерывания системы времени.
В общем, кто по этому поводу что может сказать?
Очень напомнило:
Однажды Ходжу Насреддина спросили:
-- Как избавиться от крыс?
-- Очень просто! - сообщил Ходжа.
-- Нужно растолочь черепки в порошок и, когда поймаешь крысу, засыпать ей это порошок в ноздри. Крыса не сможет дышать и издохнет.
-- Но если я поймал крысу, не проще ли убить ее, ударив об стену?
-- Конечно проще! - ответил Ходжа.
Вечер. Отец с сыном гуляют по берегу реки. На берегу сидит художник и рисует воду, мост через реку, закат...
Отец сыну(наставительно):
- Видишь, как дядя мучается без фотоаппарата?
1
количество пиксельная
2
пикселей частота,
3
в строке МГц
4
360 7.66 МГц
5
480 10.2 МГц
6
512 10.9 МГц
7
640 13.6 МГц
В то же время ширина спектра сигнала изображения составляет 6.25 МГц, что соответствует пикселной частоте 12.5 МГц.
001
#define TICK_PIX 7 // тиков (72 МГц) на пиксель, пиксельная частота =72000000/TICK_PIX
002
#define HS_PERIOD 4592 // 63.5-64 мс, 4572-4608 тактов, такты должны дельтся на TICK_PIX, для 7 оптимально 4592, для 6 - 4608
003
#define HS_START 1 // точка отсчета, условный 0, - начало импульса вертикальной синхронизации
004
#define HS_SYN_END 340 // конец импульса синхронизации 4.7 мкс
005
#define HS_SCREEN_START 837 // начало видимой части экрана 11.53 мс (831)
006
#define SCREEN_TICK_WIDTH (SCREEN_WIDTH*TICK_PIX) // =3360 - ширина видимой части экрана
007
#define HS_SCREEN_END (SCREEN_TICK_WIDTH + HS_SCREEN_START) // =4191 - примерная точка конца видимой части экрана 58.17 мкс
008
#define NUM_SCAN_LINES 240 // количество линий растра
009
#define SCREEN_WIDTH 480 // ширина видимой части экрана в пискелях
010
#define SCR_BUFFER_WIDTH 65 // длина строки видеобуфера в байтах (64 байта = 512 пикселей макс. + 1 байт-бордюр, обеспечивающий гашение луча)
011
012
#include <SPI.h>
013
#include "a_Small_Rus.c"
014
#include "font_c.c"
015
016
#define ph0 0 //LOW
017
#define ph1 1 //HIGH
018
019
#define PB00_Out (*((volatile unsigned long *) 0x42218180 )) //
020
#define PB01_Out (*((volatile unsigned long *) 0x42218184 )) //
021
#define PB02_Out (*((volatile unsigned long *) 0x42218188 )) //
022
#define PB03_Out (*((volatile unsigned long *) 0x4221818C )) //
023
#define PB04_Out (*((volatile unsigned long *) 0x42218190 )) //
024
#define PB05_Out (*((volatile unsigned long *) 0x42218194 )) //
025
#define PB06_Out (*((volatile unsigned long *) 0x42218198 )) //
026
#define PB07_Out (*((volatile unsigned long *) 0x4221819C )) //
027
#define PB08_Out (*((volatile unsigned long *) 0x422181A0 )) //
028
#define PB09_Out (*((volatile unsigned long *) 0x422181A4 )) //
029
#define PB10_Out (*((volatile unsigned long *) 0x422181A8 )) //
030
#define PB11_Out (*((volatile unsigned long *) 0x422181AC )) //
031
#define PB12_Out (*((volatile unsigned long *) 0x422181B0 )) //
032
#define PB13_Out (*((volatile unsigned long *) 0x422181B4 )) //
033
#define PB14_Out (*((volatile unsigned long *) 0x422181B8 )) //
034
#define PB15_Out (*((volatile unsigned long *) 0x422181BC )) //
035
036
#define pin_B6 PB06_Out // PB6
037
#define pin_video PB07_Out // PB7
038
#define pin_gash PB08_Out // PB8
039
#define pin_sync PB09_Out // PB9
040
041
#define NOP __asm__ __volatile__ ("nop\n\t")
042
043
byte
buf[SCR_BUFFER_WIDTH*NUM_SCAN_LINES];
// 65*240=15600 экранный буфер
044
int
lineNumber = 0;
// текущий номер строки при сканировании видеопамяти
045
int
toHS = ph1;
// ячейка для запоминания состояния HS - сразу по прерыванию заносится в порт, а потом вычисляется значение для следующей строки
046
uint32_t lenLine = 64;
// длина видимой части строки в байтах, зависит только от режима: 60 при 480 пикселях и 64 - при 512
047
int
deltaLine = 0;
// ячейка для хранения смещения строки для очередной строки растра
048
int
Xchar, Ychar;
// пиксельные координаты верхнего левого угла текущего знакоместа (куда выводим символ)
049
void
(*putChar)(unsigned
char
);
// текущая процедура вывода символа на экран
050
051
inline
void
startHS() {
// начало импульса HS, переводится из высокого состояния в низкое
052
pin_sync = ph0;
053
}
054
055
inline
void
endHS() {
// конец импульса HS, остается низким во время кадровой синхронизации
056
pin_sync = toHS;
057
toHS = (lineNumber <= 247) || (lineNumber >= 255);
// импульс VS 262-275
058
}
059
060
inline
void
endScreen() {
// конец видимой строки экрана, пока ничего не делаем, но вдруг понадибится...
061
}
062
063
inline
void
startScreen() {
064
if
(lineNumber < NUM_SCAN_LINES) {
065
pin_B6 = ph0;
066
DMA1_BASE->CCR3 &= 0xfffe;
//|= 0;
067
DMA1_BASE->CMAR3 = (uint32)&buf[deltaLine];
068
DMA1_BASE->CNDTR3 = lenLine+1;
069
DMA1_BASE->CCR3 = 0x3091;
// 0x3093
070
SPI1_BASE->CR1 = 0xC2C8;
// 0xffbf; // 0x021C;
071
pin_B6 = ph1;
072
TIMER2_BASE->CCER = 0x0010;
// CC2 enable
073
}
074
lineNumber++;
075
deltaLine += SCR_BUFFER_WIDTH;
076
if
(lineNumber >= 292) {
// 288 конец кадра
077
lineNumber = 0;
078
deltaLine = 0;
079
}
080
}
081
082
void
inline setPixel(
int
x,
int
y) {
083
buf[x/8 + y*SCR_BUFFER_WIDTH] |= 1 << (x%8);
084
}
085
086
void
inline clearPixel(
int
x,
int
y) {
087
buf[x/8 + y*SCR_BUFFER_WIDTH] &= ~(1 << (x%8));
088
}
089
090
void
putChar6x8(unsigned
char
ch) {
091
for
(
int
i = 0; i < 5; i++) {
092
byte
b = SmallFont6[(ch -
' '
)*5 + 4 + i];
093
for
(
int
j = 0; j < 8; j++) {
094
if
(b & 1) setPixel(Xchar, Ychar+j);
095
else
clearPixel(Xchar, Ychar+j);
096
b = b >> 1;
097
}
098
Xchar++;
099
}
100
for
(
int
j = 0; j < 8; j++)
101
clearPixel(Xchar, Ychar+j);
102
Xchar++;
103
}
104
105
void
putChar8x8(unsigned
char
ch) {
106
for
(
int
i = 0; i < 8; i++) {
107
buf[Xchar/8 + (Ychar + i)*SCR_BUFFER_WIDTH] = font_c[(ch -
' '
)*8 + i];
108
}
109
Xchar += 8;
110
}
111
112
void
scrollUp() {
113
memcpy(&buf[0], &buf[8*SCR_BUFFER_WIDTH], (NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH);
114
memset(&buf[(NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH], 0, 8*SCR_BUFFER_WIDTH);
115
Xchar = 0;
116
Ychar = (NUM_SCAN_LINES - 8);
117
}
118
119
void
chessField() {
120
for
(
int
i = 0; i < (15600); i++) {
121
int
L = i/SCR_BUFFER_WIDTH;
122
int
J = i%SCR_BUFFER_WIDTH;
123
int
L0 = L/16&1;
124
int
J0 = J/2&1;
125
buf[i] = 255*((L0+J0)&1);
126
}
127
for
(
int
i = 0; i < NUM_SCAN_LINES; i++)
if
(buf[i*SCR_BUFFER_WIDTH] == 0) buf[i*SCR_BUFFER_WIDTH] = 2;
else
buf[i*SCR_BUFFER_WIDTH] = 253;
//
128
}
129
130
void
screenInit() {
131
for
(
int
i = 0; i < NUM_SCAN_LINES; i++) buf[i*SCR_BUFFER_WIDTH+lenLine] = 0;
// заполнение последнего байта в строке нулями - гашение луча
132
133
GPIOB_BASE->CRL = 0x33444444;
// пины PB7,PB6 - выход, остальные - вход (не исп.)
134
GPIOB_BASE->CRH = 0x44444433;
// пины PB9-PB8 - выход, остальные - вход (не исп.)
135
GPIOA_BASE->CRL = 0xbb4444b4;
// пины MOSI(pa7), MISO(pa6), SCK(pa5), T2C2(PA1) - выход таймера
136
// GPIOA_BASE->CRL = 0xbb4444b4; // пины MOSI(pa7), MISO(pa6), SCK(pa5), T2C2(PA1) - выход таймера
137
138
RCC_BASE->AHBENR |= 0x00000001;
// включение тактового сигнала DMA
139
RCC_BASE->APB2ENR |= (1 << 12);
// включение тактового сигнала SPI
140
DMA1_BASE->CPAR3 = 0x4001300C;
141
DMA1_BASE->CMAR3 = (uint32)buf;
142
DMA1_BASE->CNDTR3 = 13;
143
SPI1_BASE->CR1 = 0xC288;
// 0xffbf; // 0x021C;
144
SPI1_BASE->CR2 = 0x0082;
// 0x0082
145
DMA1_BASE->CCR3 = 0x3090;
// 0x3092
146
147
Timer4.pause();
// while we configure
148
Timer4.setPrescaleFactor(1);
// Full speed
149
Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
150
Timer4.setChannel2Mode(TIMER_OUTPUTCOMPARE);
151
Timer4.setChannel3Mode(TIMER_OUTPUTCOMPARE);
152
Timer4.setChannel4Mode(TIMER_OUTPUTCOMPARE);
153
Timer4.setOverflow(HS_PERIOD - 1);
// 4591 : 63.7 ms, для делителя 7 оптимально 4592-1
154
155
Timer4.setCompare1(HS_START);
// 1 - начало отсчета
156
Timer4.attachCompare1Interrupt(startHS);
// начало HS
157
Timer4.setCompare2(HS_SYN_END);
// 339 - конец импульса синхронизации 4.7 мкс
158
Timer4.attachCompare2Interrupt(endHS);
// конец HS
159
Timer4.setCompare3(HS_SCREEN_START);
// 831 - начало видимой части экрана 11.53 мс
160
Timer4.attachCompare3Interrupt(startScreen);
// начало видимой строки
161
Timer4.setCompare4(HS_SCREEN_END);
// =4191 - примерная точка конца видимой части экрана 58.17 мкс
162
Timer4.attachCompare4Interrupt(endScreen);
163
164
Timer4.setCount(0);
// Ready...
165
Timer4.resume();
// Go!
166
167
TIMER2_BASE->PSC = 0;
// prescaler
168
TIMER2_BASE->ARR = TICK_PIX - 1;
// 6=7-1, где 7 - количество тиков (72МГц) на пиксель
169
TIMER2_BASE->CCR2 = TICK_PIX/2 - 1;
// 2
170
TIMER2_BASE->CCER = 0x0010;
// CC2 enable
171
delayMicroseconds(40);
172
}
173
174
void
setup
() {
175
Serial
.begin(115200);
// Ignored by Maple. But needed by boards using hardware serial via a USB to Serial adaptor ]'
176
while
(!
Serial
) ;
177
178
uint32_t t0 = micros();
179
scrollUp();
180
181
uint32_t t1 = micros();
182
chessField();
183
184
uint32_t t2 = micros();
185
for
(
int
i = 0; i < 240; i++) setPixel(i, i);
// диагональная линия
186
187
uint32_t t3 = micros();
188
Xchar = 0;
189
Ychar = 36;
190
putChar = putChar6x8;
191
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
192
193
uint32_t t4 = micros();
194
Xchar = 0;
195
Ychar = 76;
196
putChar = putChar8x8;
197
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
198
199
uint32_t t5 = micros();
200
201
Serial
.print(
"Scroll Up "
);
202
Serial
.println(t1-t0);
203
Serial
.print(
"Chess Field "
);
204
Serial
.println(t2-t1);
205
Serial
.print(
"240 pixels "
);
206
Serial
.println(t3-t2);
207
Serial
.print(
"60 chars 6x8 "
);
208
Serial
.println(t4-t3);
209
Serial
.print(
"60 chars 8x8 "
);
210
Serial
.println(t5-t4);
211
212
Xchar = 0;
213
Ychar = 207;
214
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
215
Xchar = 0;
216
Ychar = 215;
217
for
(
int
i = 59; i < 119; i++) putChar(
' '
+ i + 1);
218
Xchar = 0;
219
Ychar = 223;
220
for
(
int
i = 118; i < 163; i++) putChar(
' '
+ i + 1);
221
222
putChar = putChar6x8;
223
Xchar = 0;
224
Ychar = 183;
225
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
226
Xchar = 0;
227
Ychar = 191;
228
for
(
int
i = 59; i < 119; i++) putChar(
' '
+ i + 1);
229
Xchar = 0;
230
Ychar = 199;
231
for
(
int
i = 118; i < 176; i++) putChar(
' '
+ i + 1);
232
233
screenInit();
234
235
// This gets rid of the majority of the interrupt artifacts;
236
// a SysTick.end() is required as well
237
// Serial.end();
238
239
putChar = putChar8x8;
240
Xchar = 480;
241
Ychar = 239;
242
}
243
244
void
loop
() {
245
if
(
Serial
.available()) {
246
unsigned
char
ch =
Serial
.read();
247
Serial
.println(ch);
248
if
(ch == 13) {
249
Xchar = 0;
250
Ychar += 8;
251
if
(Ychar > (NUM_SCAN_LINES-8)) {
252
scrollUp();
253
}
254
ch = 0;
255
}
256
if
(Xchar > 472) {
257
scrollUp();
258
}
259
if
(ch != 0) putChar(ch);
260
}
261
}
001
#if defined(__AVR__)
002
#include <avr/pgmspace.h>
003
#define fontdatatype const uint8_t
004
#elif defined(__PIC32MX__)
005
#define PROGMEM
006
#define fontdatatype const unsigned char
007
#elif defined(__arm__)
008
#define PROGMEM
009
#define fontdatatype const unsigned char
010
#endif
011
012
// New font 177 symbols 5x8 = 885+4 bytes
013
014
fontdatatype SmallFont6[] PROGMEM =
015
{
016
0x05, 0x08, 0x20, 0xb1,
017
0x00, 0x00, 0x00, 0x00, 0x00,
// sp
018
0x00, 0x00, 0x2f, 0x00, 0x00,
// !
019
0x00, 0x07, 0x00, 0x07, 0x00,
// "
020
0x14, 0x7f, 0x14, 0x7f, 0x14,
// #
021
0x24, 0x2a, 0x7f, 0x2a, 0x12,
// $
022
0x23, 0x13, 0x08, 0x64, 0x62,
// %
023
0x36, 0x49, 0x55, 0x22, 0x50,
// &
024
0x00, 0x05, 0x03, 0x00, 0x00,
// '
025
0x00, 0x1c, 0x22, 0x41, 0x00,
// (
026
0x00, 0x41, 0x22, 0x1c, 0x00,
// )
027
0x14, 0x08, 0x3E, 0x08, 0x14,
// *
028
0x08, 0x08, 0x3E, 0x08, 0x08,
// +
029
0x00, 0x00, 0xA0, 0x60, 0x00,
// ,
030
0x08, 0x08, 0x08, 0x08, 0x08,
// -
031
0x00, 0x60, 0x60, 0x00, 0x00,
// .
032
0x20, 0x10, 0x08, 0x04, 0x02,
// /
033
034
0x3E, 0x51, 0x49, 0x45, 0x3E,
// 0
035
0x00, 0x42, 0x7F, 0x40, 0x00,
// 1
036
0x42, 0x61, 0x51, 0x49, 0x46,
// 2
037
0x21, 0x41, 0x45, 0x4B, 0x31,
// 3
038
0x18, 0x14, 0x12, 0x7F, 0x10,
// 4
039
0x27, 0x45, 0x45, 0x45, 0x39,
// 5
040
0x3C, 0x4A, 0x49, 0x49, 0x30,
// 6
041
0x01, 0x71, 0x09, 0x05, 0x03,
// 7
042
0x36, 0x49, 0x49, 0x49, 0x36,
// 8
043
0x06, 0x49, 0x49, 0x29, 0x1E,
// 9
044
0x00, 0x36, 0x36, 0x00, 0x00,
// :
045
0x00, 0x56, 0x36, 0x00, 0x00,
// ;
046
0x08, 0x14, 0x22, 0x41, 0x00,
// <
047
0x14, 0x14, 0x14, 0x14, 0x14,
// =
048
0x00, 0x41, 0x22, 0x14, 0x08,
// >
049
0x02, 0x01, 0x51, 0x09, 0x06,
// ?
050
051
0x32, 0x49, 0x59, 0x51, 0x3E,
// @
052
0x7C, 0x12, 0x11, 0x12, 0x7C,
// A
053
0x7F, 0x49, 0x49, 0x49, 0x36,
// B
054
0x3E, 0x41, 0x41, 0x41, 0x22,
// C
055
0x7F, 0x41, 0x41, 0x22, 0x1C,
// D
056
0x7F, 0x49, 0x49, 0x49, 0x41,
// E
057
0x7F, 0x09, 0x09, 0x09, 0x01,
// F
058
0x3E, 0x41, 0x49, 0x49, 0x7A,
// G
059
0x7F, 0x08, 0x08, 0x08, 0x7F,
// H
060
0x00, 0x41, 0x7F, 0x41, 0x00,
// I
061
0x20, 0x40, 0x41, 0x3F, 0x01,
// J
062
0x7F, 0x08, 0x14, 0x22, 0x41,
// K
063
0x7F, 0x40, 0x40, 0x40, 0x40,
// L
064
0x7F, 0x02, 0x0C, 0x02, 0x7F,
// M
065
0x7F, 0x04, 0x08, 0x10, 0x7F,
// N
066
0x3E, 0x41, 0x41, 0x41, 0x3E,
// O
067
068
0x7F, 0x09, 0x09, 0x09, 0x06,
// P
069
0x3E, 0x41, 0x51, 0x21, 0x5E,
// Q
070
0x7F, 0x09, 0x19, 0x29, 0x46,
// R
071
0x46, 0x49, 0x49, 0x49, 0x31,
// S
072
0x01, 0x01, 0x7F, 0x01, 0x01,
// T
073
0x3F, 0x40, 0x40, 0x40, 0x3F,
// U
074
0x1F, 0x20, 0x40, 0x20, 0x1F,
// V
075
0x3F, 0x40, 0x38, 0x40, 0x3F,
// W
076
0x63, 0x14, 0x08, 0x14, 0x63,
// X
077
0x07, 0x08, 0x70, 0x08, 0x07,
// Y
078
0x61, 0x51, 0x49, 0x45, 0x43,
// Z
079
0x00, 0x7F, 0x41, 0x41, 0x00,
// [
080
0x01, 0x06, 0x08, 0x30, 0x40,
// Backslash
081
0x00, 0x41, 0x41, 0x7F, 0x00,
// ]
082
0x04, 0x02, 0x01, 0x02, 0x04,
// ^
083
0x40, 0x40, 0x40, 0x40, 0x40,
// _
084
085
0x00, 0x03, 0x05, 0x00, 0x00,
// `
086
0x20, 0x54, 0x54, 0x54, 0x78,
// a
087
0x7F, 0x48, 0x44, 0x44, 0x38,
// b
088
0x38, 0x44, 0x44, 0x44, 0x20,
// c
089
0x38, 0x44, 0x44, 0x48, 0x7F,
// d
090
0x38, 0x54, 0x54, 0x54, 0x18,
// e
091
0x08, 0x7E, 0x09, 0x01, 0x02,
// f
092
0x18, 0xA4, 0xA4, 0xA4, 0x7C,
// g
093
0x7F, 0x08, 0x04, 0x04, 0x78,
// h
094
0x00, 0x44, 0x7D, 0x40, 0x00,
// i
095
0x40, 0x80, 0x84, 0x7D, 0x00,
// j
096
0x7F, 0x10, 0x28, 0x44, 0x00,
// k
097
0x00, 0x41, 0x7F, 0x40, 0x00,
// l
098
0x7C, 0x04, 0x18, 0x04, 0x78,
// m
099
0x7C, 0x08, 0x04, 0x04, 0x78,
// n
100
0x38, 0x44, 0x44, 0x44, 0x38,
// o
101
102
0xFC, 0x24, 0x24, 0x24, 0x18,
// p
103
0x18, 0x24, 0x24, 0x18, 0xFC,
// q
104
0x7C, 0x08, 0x04, 0x04, 0x08,
// r
105
0x48, 0x54, 0x54, 0x54, 0x20,
// s
106
0x04, 0x3F, 0x44, 0x40, 0x20,
// t
107
0x3C, 0x40, 0x40, 0x20, 0x7C,
// u
108
0x1C, 0x20, 0x40, 0x20, 0x1C,
// v
109
0x3C, 0x40, 0x30, 0x40, 0x3C,
// w
110
0x44, 0x28, 0x10, 0x28, 0x44,
// x
111
0x1C, 0xA0, 0xA0, 0xA0, 0x7C,
// y
112
0x44, 0x64, 0x54, 0x4C, 0x44,
// z
113
0x00, 0x10, 0x7C, 0x82, 0x00,
// {
114
0x00, 0x00, 0xFF, 0x00, 0x00,
// |
115
0x00, 0x82, 0x7C, 0x10, 0x00,
// }
116
0x08, 0x04, 0x08, 0x10, 0x08,
// 7E 126 ~
117
0x7C, 0x12, 0x11, 0x12, 0x7C,
// А
118
119
0x7F, 0x49, 0x49, 0x49, 0x31,
// Б
120
0x7F, 0x45, 0x45, 0x45, 0x3A,
// В
121
0x7F, 0x01, 0x01, 0x01, 0x03,
// Г
122
0x60, 0x3F, 0x21, 0x3F, 0x60,
// Д
123
0x7F, 0x49, 0x49, 0x49, 0x41,
// Е
124
0x73, 0x0C, 0x7F, 0x0C, 0x73,
// Ж
125
0x21, 0x41, 0x49, 0x4D, 0x33,
// З
126
0x7F, 0x10, 0x08, 0x04, 0x7F,
// И
127
0x7E, 0x20, 0x11, 0x08, 0x7E,
// Й
128
0x7F, 0x08, 0x14, 0x22, 0x41,
// К
129
0x40, 0x3F, 0x01, 0x01, 0x7F,
// Л
130
0x7F, 0x06, 0x08, 0x06, 0x7F,
// М
131
0x7F, 0x08, 0x08, 0x08, 0x7F,
// Н
132
0x3E, 0x41, 0x41, 0x41, 0x3E,
// О
133
0x7F, 0x01, 0x01, 0x01, 0x7F,
// П
134
0x7F, 0x09, 0x09, 0x09, 0x06,
// Р
135
136
0x3E, 0x41, 0x41, 0x41, 0x22,
// С
137
0x03, 0x01, 0x7F, 0x01, 0x03,
// Т
138
0x61, 0x26, 0x18, 0x06, 0x01,
// У
139
0x1C, 0x22, 0x7F, 0x22, 0x1C,
// Ф
140
0x63, 0x14, 0x08, 0x14, 0x63,
// Х
141
0x3F, 0x20, 0x20, 0x3F, 0x60,
// Ц
142
0x07, 0x08, 0x08, 0x08, 0x7F,
// Ч
143
0x7F, 0x40, 0x7F, 0x40, 0x7F,
// Ш
144
0x3F, 0x20, 0x3F, 0x20, 0x7F,
// Щ
145
0x01, 0x7F, 0x48, 0x48, 0x30,
// Ъ
146
0x7F, 0x48, 0x78, 0x00, 0x7F,
// Ы
147
0x7F, 0x48, 0x48, 0x30, 0x00,
// Ь
148
0x41, 0x49, 0x49, 0x2A, 0x1C,
// Э
149
0x7F, 0x10, 0x3E, 0x41, 0x3E,
// Ю
150
0x66, 0x19, 0x09, 0x09, 0x7F,
// Я
151
0x20, 0x54, 0x54, 0x78, 0x40,
// а
152
153
0x3E, 0x49, 0x45, 0x45, 0x38,
// б
154
0x7E, 0x4A, 0x4A, 0x34, 0x00,
// в
155
0x7C, 0x04, 0x04, 0x0C, 0x00,
// г
156
0x38, 0x45, 0x45, 0x49, 0x3E,
// д
157
0x38, 0x54, 0x54, 0x54, 0x18,
// е
158
0x4C, 0x30, 0x7C, 0x30, 0x4C,
// ж
159
0x24, 0x42, 0x4A, 0x34, 0x00,
// з
160
0x7C, 0x20, 0x10, 0x7C, 0x00,
// и
161
0x7C, 0x21, 0x11, 0x7C, 0x00,
// й
162
0x7C, 0x10, 0x28, 0x44, 0x00,
// к
163
0x40, 0x3C, 0x04, 0x04, 0x7C,
// л
164
0x7C, 0x08, 0x10, 0x08, 0x7C,
// м
165
0x7C, 0x10, 0x10, 0x7C, 0x00,
// н
166
0x38, 0x44, 0x44, 0x44, 0x38,
// о
167
0x7C, 0x04, 0x04, 0x7C, 0x00,
// п
168
0xFC, 0x18, 0x24, 0x24, 0x18,
// р
169
170
0x38, 0x44, 0x44, 0x44, 0x28,
// с
171
0x04, 0x04, 0x7C, 0x04, 0x04,
// т
172
0x4C, 0x90, 0x90, 0x90, 0x7C,
// у
173
0x18, 0x24, 0x7E, 0x24, 0x18,
// ф
174
0x44, 0x28, 0x10, 0x28, 0x44,
// х
175
0x3C, 0x20, 0x20, 0x3C, 0x60,
// ц
176
0x1C, 0x10, 0x10, 0x7C, 0x00,
// ч
177
0x7C, 0x40, 0x7C, 0x40, 0x7C,
// ш
178
0x3C, 0x20, 0x3C, 0x20, 0x7C,
// щ
179
0x04, 0x7C, 0x50, 0x70, 0x00,
// ъ
180
0x7C, 0x50, 0x70, 0x00, 0x7C,
// ы
181
0x7C, 0x50, 0x70, 0x00, 0x00,
// ь
182
0x42, 0x42, 0x52, 0x52, 0x3C,
// э
183
0x7C, 0x10, 0x38, 0x44, 0x38,
// ю
184
0x40, 0x2C, 0x12, 0x7E, 0x00,
// я
185
0x7E, 0x4B, 0x4A, 0x4B, 0x42,
// Ё D0 81
186
187
0x38, 0x55, 0x54, 0x55, 0x18,
// ё D1 91
188
0x7C, 0x04, 0x05, 0x04, 0x00,
//81 129 Ѓ D0 83
189
0x00, 0x78, 0x0A, 0x09, 0x00,
//83 131 ѓ D1 93
190
0x3E, 0x49, 0x49, 0x41, 0x22,
//AA 170 Є D0 84
191
0x38, 0x54, 0x54, 0x44, 0x28,
//BA 186 є D1 94
192
0x00, 0x41, 0x7F, 0x41, 0x00,
//B2 178 І D0 86
193
0x00, 0x44, 0x7D, 0x40, 0x00,
//B3 179 і D1 96
194
0x00, 0x45, 0x7C, 0x45, 0x00,
//AF 175 Ї D0 87
195
0x00, 0x45, 0x7C, 0x41, 0x00,
//BF 191 ї D1 97
196
0x23, 0x44, 0x39, 0x04, 0x03,
//A1 161 Ў D0 8E
197
0x24, 0x49, 0x32, 0x09, 0x04,
//A2 162 ў D1 9E
198
0x7E, 0x02, 0x02, 0x02, 0x01,
//A5 165 Ґ D2 90
199
0x7C, 0x04, 0x04, 0x02, 0x00,
//B4 180 ґ D2 91
200
0x00, 0x4A, 0x55, 0x29, 0x00,
//A7 167 § C2 A7
201
0x00, 0x06, 0x09, 0x09, 0x06,
// ° C2 B0
202
0x44, 0x44, 0x5F, 0x44, 0x44,
//B1 177 ± C2 B1
203
204
0x7C, 0x10, 0x10, 0x3C, 0x40,
//B5 181 µ C2 B5
205
};
001
#include <avr/pgmspace.h>
002
003
const
unsigned
char
font_c[] PROGMEM = {
004
0, 0, 0, 0, 0, 0, 0, 0,
// 32
005
24, 60, 60, 24, 24, 0, 24, 0,
// 33 !
006
54, 54, 20, 0, 0, 0, 0, 0,
// 34 "
007
54, 54, 127, 54, 127, 54, 54, 0,
// 35 #
008
8, 60, 2, 28, 32, 30, 8, 0,
// 36 $
009
6, 102, 48, 24, 12, 102, 96, 0,
// 37 %
010
30, 51, 30, 10, 83, 51, 126, 0,
// 38 &
011
24, 24, 24, 12, 0, 0, 0, 0,
// 39 '
012
48, 24, 12, 12, 12, 24, 48, 0,
// 40 (
013
12, 24, 48, 48, 48, 24, 12, 0,
// 41 )
014
0, 54, 28, 127, 28, 54, 0, 0,
// 42 *
015
0, 8, 8, 62, 8, 8, 0, 0,
// 43 +
016
0, 0, 0, 24, 24, 24, 12, 0,
// 44 ,
017
0, 0, 0, 60, 0, 0, 0, 0,
// 45 -
018
0, 0, 0, 0, 0, 24, 24, 0,
// 46 .
019
0, 96, 48, 24, 12, 6, 0, 0,
// 47 /
020
60, 102, 118, 110, 102, 102, 60, 0,
// 48 0
021
24, 24, 28, 24, 24, 24, 126, 0,
// 49 1
022
60, 102, 96, 48, 12, 6, 126, 0,
// 50 2
023
60, 102, 96, 56, 96, 102, 60, 0,
// 51 3
024
48, 56, 52, 50, 126, 48, 48, 0,
// 52 4
025
126, 6, 62, 96, 96, 102, 60, 0,
// 53 5
026
60, 102, 6, 62, 102, 102, 60, 0,
// 54 6
027
126, 102, 48, 48, 24, 24, 24, 0,
// 55 7
028
60, 102, 102, 60, 102, 102, 60, 0,
// 56 8
029
60, 102, 102, 124, 96, 102, 60, 0,
// 57 9
030
0, 24, 24, 0, 24, 24, 0, 0,
// 58 :
031
0, 24, 24, 0, 24, 24, 12, 0,
// 59 ;
032
48, 24, 12, 6, 12, 24, 48, 0,
// 60 <
033
0, 0, 60, 0, 60, 0, 0, 0,
// 61 =
034
6, 12, 24, 48, 24, 12, 6, 0,
// 62 >
035
60, 102, 96, 56, 24, 0, 24, 0,
// 63 ?
036
28, 34, 58, 26, 66, 60, 0, 0,
// 64 @
037
60, 102, 102, 126, 102, 102, 102, 0,
// 65 A
038
62, 102, 102, 62, 102, 102, 62, 0,
// 66 B
039
60, 102, 6, 6, 6, 102, 60, 0,
// 67 C
040
62, 102, 102, 102, 102, 102, 62, 0,
// 68 D
041
126, 6, 6, 62, 6, 6, 126, 0,
// 69 E
042
126, 6, 6, 62, 6, 6, 6, 0,
// 70 F
043
60, 102, 6, 6, 118, 102, 60, 0,
// 71 G
044
102, 102, 102, 126, 102, 102, 102, 0,
// 72 H
045
60, 24, 24, 24, 24, 24, 60, 0,
// 73 I
046
120, 48, 48, 48, 54, 54, 28, 0,
// 74 J
047
102, 54, 30, 14, 30, 54, 102, 0,
// 75 K
048
6, 6, 6, 6, 6, 6, 126, 0,
// 76 L
049
99, 119, 127, 107, 99, 99, 99, 0,
// 77 M
050
99, 103, 111, 123, 115, 99, 99, 0,
// 78 N
051
60, 102, 102, 102, 102, 102, 60, 0,
// 79 O
052
62, 102, 102, 102, 62, 6, 6, 0,
// 80 P
053
60, 102, 102, 102, 118, 60, 96, 0,
// 81 Q
054
62, 102, 102, 62, 30, 54, 102, 0,
// 82 R
055
60, 102, 6, 60, 96, 102, 60, 0,
// 83 S
056
126, 90, 24, 24, 24, 24, 24, 0,
// 84 T
057
102, 102, 102, 102, 102, 102, 124, 0,
// 85 U
058
102, 102, 102, 102, 102, 60, 24, 0,
// 86 V
059
99, 99, 99, 107, 127, 119, 99, 0,
// 87 W
060
99, 99, 54, 28, 54, 99, 99, 0,
// 88 X
061
102, 102, 102, 60, 24, 24, 24, 0,
// 89 Y
062
126, 96, 48, 24, 12, 6, 126, 0,
// 90 Z
063
60, 12, 12, 12, 12, 12, 60, 0,
// 91 [
064
0, 6, 12, 24, 48, 96, 0, 0,
// 92 BackSlash
065
60, 48, 48, 48, 48, 48, 60, 0,
// 93 ]
066
8, 20, 34, 65, 0, 0, 0, 0,
// 94 ^
067
0, 0, 0, 0, 0, 0, 60, 0,
// 95 _
068
12, 12, 24, 0, 0, 0, 0, 0,
// 96 `
069
0, 0, 60, 96, 124, 102, 124, 0,
// 97 a
070
6, 6, 6, 62, 102, 102, 62, 0,
// 98 b
071
0, 0, 60, 102, 6, 102, 60, 0,
// 99 c
072
96, 96, 96, 124, 102, 102, 124, 0,
// 100 d
073
0, 0, 60, 102, 126, 6, 60, 0,
// 101 e
074
56, 108, 12, 12, 62, 12, 12, 0,
// 102 f
075
0, 124, 102, 102, 124, 96, 60, 0,
// 103 g
076
6, 6, 6, 62, 102, 102, 102, 0,
// 104 h
077
0, 6, 0, 6, 6, 6, 79, 0,
// 105 i
078
48, 0, 48, 48, 54, 54, 28, 0,
// 106 j
079
6, 6, 102, 54, 30, 54, 102, 0,
// 107 k
080
24, 24, 24, 24, 24, 24, 24, 0,
// 108 l
081
0, 0, 99, 119, 127, 107, 107, 0,
// 109 m
082
0, 0, 62, 126, 102, 102, 102, 0,
// 110 n
083
0, 0, 60, 102, 102, 102, 60, 0,
// 111 o
084
0, 62, 102, 102, 62, 6, 6, 0,
// 112 p
085
0, 30, 27, 27, 30, 88, 120, 0,
// 113 q
086
0, 0, 62, 102, 102, 6, 6, 0,
// 114 r
087
0, 0, 124, 2, 60, 64, 62, 0,
// 115 s
088
0, 24, 24, 126, 24, 24, 24, 0,
// 116 t
089
0, 0, 102, 102, 102, 102, 124, 0,
// 117 u
090
0, 0, 0, 102, 102, 60, 24, 0,
// 118 v
091
0, 0, 99, 107, 107, 107, 62, 0,
// 119 w
092
0, 0, 102, 60, 24, 60, 102, 0,
// 120 x
093
0, 0, 102, 102, 124, 96, 60, 0,
// 121 y
094
0, 0, 60, 48, 24, 12, 60, 0,
// 122 z
095
56, 12, 12, 6, 12, 12, 56, 0,
// 123 {
096
8, 8, 8, 8, 8, 8, 8, 0,
// 124 |
097
14, 24, 24, 48, 24, 24, 14, 0,
// 125 }
098
0, 0, 92, 54, 0, 0, 0, 0,
// 126 ~
099
0, 0, 0, 0, 0, 0, 0, 0,
// 127 BackSpace
100
0, 62, 102, 102, 62, 6, 6, 0,
// 128 Р
101
0, 0, 60, 102, 6, 102, 60, 0,
// 129 с
102
0, 0, 126, 24, 24, 24, 24, 0,
// 130 т
103
0, 0, 102, 102, 124, 96, 60, 0,
// 131 у
104
0, 0, 60, 90, 90, 90, 60, 24,
// 132 ф
105
0, 0, 102, 60, 24, 60, 102, 0,
// 133 х
106
0, 0, 51, 51, 51, 51, 127, 96,
// 134 ц
107
0, 0, 102, 102, 126, 96, 96, 0,
// 135 ч
108
0, 0, 99, 107, 107, 107, 127, 0,
// 136 ш
109
0, 0, 99, 107, 107, 107, 255, 192,
// 137 щ
110
0, 0, 7, 62, 102, 102, 62, 0,
// 138 ъ
111
0, 0, 195, 207, 219, 219, 207, 0,
// 139 ы
112
0, 0, 6, 62, 102, 102, 62, 0,
// 140 ь
113
0, 0, 60, 98, 120, 98, 60, 0,
// 141 э
114
0, 0, 115, 219, 223, 219, 115, 0,
// 142 ю
115
0, 0, 124, 102, 126, 108, 102, 0,
// 143 я
116
60, 102, 102, 126, 102, 102, 102, 0,
// 144 А
117
126, 6, 62, 102, 102, 102, 62, 0,
// 145 Б
118
62, 102, 102, 62, 102, 102, 62, 0,
// 146 В
119
126, 6, 6, 6, 6, 6, 6, 0,
// 147 Г
120
56, 52, 54, 54, 54, 54, 127, 99,
// 148 Д
121
126, 6, 6, 62, 6, 6, 126, 0,
// 149 Е
122
219, 219, 90, 188, 90, 219, 219, 0,
// 150 Ж
123
60, 102, 96, 56, 96, 102, 60, 0,
// 151 З
124
102, 102, 102, 102, 118, 110, 102, 0,
// 152 И
125
24, 0, 102, 102, 118, 110, 102, 0,
// 153 Й
126
102, 54, 30, 14, 30, 54, 102, 0,
// 154 К
127
112, 104, 108, 108, 108, 108, 110, 0,
// 155 Л
128
99, 119, 127, 107, 99, 99, 99, 0,
// 156 М
129
102, 102, 102, 126, 102, 102, 102, 0,
// 157 Н
130
60, 102, 102, 102, 102, 102, 60, 0,
// 158 О
131
126, 102, 102, 102, 102, 102, 102, 0,
// 159 П
132
62, 102, 102, 102, 62, 6, 6, 0,
// 160 Р
133
60, 102, 6, 6, 6, 102, 60, 0,
// 161 С
134
126, 90, 24, 24, 24, 24, 24, 0,
// 162 Т
135
102, 102, 102, 124, 96, 102, 60, 0,
// 163 У
136
126, 219, 219, 219, 254, 24, 24, 0,
// 164 Ф
137
99, 99, 54, 28, 54, 99, 99, 0,
// 165 Х
138
51, 51, 51, 51, 51, 51, 127, 96,
// 166 Ц
139
102, 102, 102, 126, 96, 96, 96, 0,
// 167 Ч
140
99, 99, 107, 107, 107, 107, 127, 0,
// 168 Ш
141
99, 99, 107, 107, 107, 107, 255, 192,
// 169 Щ
142
7, 7, 62, 102, 230, 102, 62, 0,
// 170 Ъ
143
195, 195, 207, 219, 219, 219, 207, 0,
// 171 Ы
144
6, 6, 62, 102, 102, 102, 62, 0,
// 172 Ь
145
60, 102, 96, 120, 96, 102, 60, 0,
// 173 Э
146
115, 219, 219, 223, 219, 219, 115, 0,
// 174 Ю
147
124, 102, 102, 102, 120, 108, 102, 0,
// 175 Я
148
0, 0, 60, 96, 124, 102, 124, 0,
// 176 а
149
64, 60, 6, 62, 102, 102, 60, 0,
// 177 б
150
12, 22, 22, 14, 62, 102, 60, 0,
// 178 в
151
0, 0, 126, 6, 6, 6, 6, 0,
// 179 г
152
0, 0, 60, 54, 54, 54, 127, 99,
// 180 д
153
0, 0, 60, 102, 126, 6, 60, 0,
// 181 е
154
0, 0, 219, 90, 60, 90, 219, 0,
// 182 ж
155
0, 0, 60, 102, 48, 102, 60, 0,
// 183 з
156
0, 0, 102, 102, 118, 110, 102, 0,
// 184 и
157
24, 0, 102, 102, 118, 110, 102, 0,
// 185 й
158
0, 0, 102, 54, 30, 54, 102, 0,
// 186 к
159
0, 0, 112, 104, 108, 108, 110, 0,
// 187 л
160
0, 0, 99, 247, 235, 99, 99, 0,
// 188 м
161
0, 0, 102, 102, 126, 102, 102, 0,
// 189 н
162
0, 0, 60, 102, 102, 102, 60, 0,
// 190 о
163
0, 0, 126, 102, 102, 102, 102, 0,
// 191 п
164
102, 0, 126, 6, 62, 6, 126, 0,
// 192 Ё
165
36, 0, 60, 102, 126, 6, 60, 0,
// 193 ё
166
0, 0, 0, 0, 0, 0, 0, 0,
// 194
167
0, 0, 0, 0, 0, 0, 0, 0
// 195
168
};
Выяснил, что после отключения USB (Serial.end()) последовательный порт (Serial1) сохраняет работоспособность.
Значит, так и будет работать: USB выключаем дабы избавиться от помех на экране, а обмен ведем через COM-порт (PA9, PA10).
Видео одного из промежуточных вариантов: https://youtu.be/kdt_LOdkxfY
Выводит на экран текст, передаваемый по последовательному порту.
Имеет два режима экрана 480х240 и 512х240 пикселей, позволяет переключаться между ними в процессе работы посредством управляющих последовательностей.
Поддерживает два фонта: 6х8 и 8х8 пикселей, которые могут присутствовать на экране одновременно. Переключаются управляющими последовательностями.
Позволяет позиционировать место вывода.
Позволяет рисовать линии посредством управляющих последовательностей.
Пока:
- нет борьбы с помехами,
- не поддерживается кириллица,
- не поддерживаются аппаратные настройки (например, переключение кодовой страницы, что будет актуально после подключения кириллицы - планируется utf-8, 866, 1251 и КОИ8).
Для записи ролика был создан сценарий, т.е. последовательность символов, передаваемая в порт. В качестве источника данных была использована Мега. К проекту она никакого отношения не имеет, вместо нее можно было использовать ардуиновский монитор порта, но я, увы, не могу соревноваться с Мегой в скорости ввода символов.
Код будет выложен ближайшие день-два.
PS. Ни у кого нет на примете фонта 8х8 (желательно жирного) с украинско-белорусской кириллицей?
А вот и обещанные исходники:
stm_strl.ino
001
#include <SPI.h>
002
#include "screen.h"
003
004
void
setup
() {
005
Serial
.begin(115200);
// Ignored by Maple. But needed by boards using hardware serial via a USB to Serial adaptor ]'
006
while
(!
Serial
) ;
007
008
uint32_t t0 = micros();
009
scrollUp();
010
011
uint32_t t1 = micros();
012
chessField();
013
014
uint32_t t2 = micros();
015
setXY(0, 0);
016
lineTo(239, 239);
017
018
uint32_t t3 = micros();
019
setXY(0, 36);
020
setCharSize6x8();
021
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
022
023
uint32_t t4 = micros();
024
setXY(0, 76);
025
setCharSize8x8();
026
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
027
028
uint32_t t5 = micros();
029
030
setXY(0, 207);
031
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
032
setXY(0, 215);
033
for
(
int
i = 59; i < 119; i++) putChar(
' '
+ i + 1);
034
setXY(0, 223);
035
for
(
int
i = 118; i < 163; i++) putChar(
' '
+ i + 1);
036
037
setCharSize6x8();
038
setXY(0, 183);
039
for
(
int
i = 0; i < 60; i++) putChar(
' '
+ i + 1);
040
setXY(0, 191);
041
for
(
int
i = 59; i < 119; i++) putChar(
' '
+ i + 1);
042
setXY(0, 199);
043
for
(
int
i = 118; i < 176; i++) putChar(
' '
+ i + 1);
044
045
Serial1.begin(9600);
046
delay(1);
047
048
setScreenMode(SCREEN_MODE_480);
049
050
// This gets rid of the majority of the interrupt artifacts;
051
// a SysTick.end() is required as well
052
// Serial.end();
053
054
055
Serial
.print(
"Scroll Up "
);
056
Serial
.println(t1-t0);
057
Serial
.print(
"Chess Field "
);
058
Serial
.println(t2-t1);
059
Serial
.print(
"Line 240 pix."
);
060
Serial
.println(t3-t2);
061
Serial
.print(
"60 chars 6x8 "
);
062
Serial
.println(t4-t3);
063
Serial
.print(
"60 chars 8x8 "
);
064
Serial
.println(t5-t4);
065
066
setCharSize8x8;
067
068
setXY(240+45, 120);
069
lineTo(240, 120+85);
070
lineTo(240-200, 120);
071
lineTo(240, 120-100);
072
lineTo(240, 120);
073
lineTo(240+45, 120);
074
075
setXY(0, 232);
076
pinMode(LED_BUILTIN, OUTPUT);
077
}
078
079
void
loop
() {
080
static
int
ledState = LOW;
// blink
081
static
unsigned
long
previousMillis = 0;
082
static
long
interval = 20;
083
unsigned
long
currentMillis = millis();
084
085
if
(currentMillis - previousMillis >= interval) {
086
previousMillis = currentMillis;
087
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
088
interval = 20 + digitalRead(LED_BUILTIN)*980;
089
}
090
if
(Serial1.available()) {
// обработка ввода
091
unsigned
char
ch = Serial1.read();
092
#ifdef DEBUG
093
if
(ch >=
' '
) {
094
Serial
.print((
char
)ch);
095
}
else
{
096
Serial
.print(
'^'
);
097
Serial
.print((
char
)(ch +
'A'
- 1));
098
}
099
Serial
.print(
" 0x"
);
100
Serial
.println((
byte
)ch,HEX);
101
#endif
102
printChar(ch);
103
}
104
}
screen.h
01
#ifndef SCREEN_H
02
#define SCREEN_H
03
04
// Библиотечка использует stm32f103 для формирования полного TV-сигнала,
05
// позволяет выводить на экран текст и рисовать линии.
06
// Возможности:
07
// Позволяет установить один из двух видеорежимов: 480х240 или 512х240 пикселей,
08
// Позволяет выводить текст фонтами размером 6х8 и 8х8 (жирный) пикселей, могут присутствовать на экране одновременно,
09
// Позволяет рисовать линии при помощи управляющих последовательностей,
10
// При выводе текста последний переносится на следующую строку по достижении правого края экрана,
11
// При достижении нижнего края - происходит скроллинг текста.
12
// Поддерживаются слежующие управляющие последовательности
13
// ]~4 - переключение в режим 480 пикселей
14
// ]~5 - переключение в режим 512 пикселей
15
// ]~6 - переключение в режим узкого шрифта 6х8
16
// ]~8 - переключение в режим широкого шрифта 8х8
17
// ]~C- очистка экрана
18
// ]~LXXXxYYY$ - рисование линии из текущей точки в указанную
19
// ]~MXXXxYYY$ - перемещение текущей позиции в указанную точку
20
// где XXX и YYY - десятичная запись одно-, двух- или трехзначных координат.
21
// управляющая последовательность может (но не обязана) заканчиваться символом перевода строки, который в этом случае опускается,
22
// в тексте символ 0x13 обрабатывается как конец строки, другие однобайтовые управляющие символы пока не поддерживаются.
23
//
24
// !!! пока не предпринимались попытки борьбы с помехами на экране !!!
25
// !!! кириллица пока не поддерживается !!!
26
27
#define SCREEN_MODE_480 0
28
#define SCREEN_MODE_512 1
29
30
extern
void
(*putChar)(unsigned
char
);
// текущая процедура вывода символа на экран
31
extern
void
scrollUp();
// пролистывание экрана на одну строку (8 пикселей) вверх и очистка последней строки
32
extern
void
chessField();
// рисует на экране "шахматное" поле с "квадратиком" 16х16 пикселей
33
extern
void
setScreenMode(
int
mode);
// установка одного из двух режимов 480х240 или 512х240 пикселей - см. определенные выше константы
34
extern
void
setCharSize6x8();
// выбор фонта 6х8 пикселей
35
extern
void
setCharSize8x8();
// выбор "жирного" фонта 8х8 пикселей
36
extern
void
setXY(uint32_t x, uint32_t y);
// устанавливает текущую позицию вывода
37
extern
void
printChar(unsigned
char
ch);
// вывод символа в текущую позицию
38
extern
void
lineTo(uint32_t x1, uint32_t y1);
// рисует линию из текущей позиции в указанную (вместо moveTo(); следует использовать setXY(); )
39
40
#endif
screen.cpp
001
#define NUM_SCAN_LINES 240 // количество линий растра экрана (видимых)
002
#define SCR_BUFFER_WIDTH 65 // длина строки видеобуфера в байтах (64 байта = 512 пикселей макс. + 1 байт-бордюр, обеспечивающий гашение луча)
003
004
#include <Arduino.h> // SCREEN_WIDTH*TICK_PIX + HS_SCREEN_START
005
#include <SPI.h>
006
#include "a_Small_Rus.c"
007
#include "font_c.c"
008
009
#define ph0 0 //LOW
010
#define ph1 1 //HIGH
011
012
#define pin_sync (*((volatile unsigned long *) 0x422181A4 )) // PB9
013
014
#include "screen.h"
015
016
struct
tv_screen {
// HS отсчитывается от начала синхроимпульса, VS - от начала первой видимой строки экрана
017
uint32_t tick_pix;
// 6 или 7 тактов (72 МГц) на пиксель, пиксельная частота =72000000/tick_pix
018
uint32_t HS_period;
// 63.5-64 мс, 4572-4608 тактов, такты кратны TICK_PIX, для tick_pix=7 - HS_period=4592, для tick_pix=6 - HS_period=4608
019
uint32_t HS_syn_end;
// 4.7 мкс - конец импульса синхронизации, в тактах
020
uint32_t HS_screen_start;
// 11.61 мкс - начало видимой части экрана (по ГОСТ 10.5 мкс), в тактах
021
uint32_t screen_width;
// 480 или 512 - ширина экрана (3072 или 3360 тактов), в пикселях
022
uint32_t VS_num_lines;
// полное количество линий развертки в кадре (288-312)
023
uint32_t VS_sync_start;
// первая строка импульса VS
024
uint32_t VS_sync_end;
// последняя строка импульса VS
025
};
026
027
uint32_t VS_num_lines;
// текущее количество линий вертикальной развертки
028
uint32_t VS_sync_start;
// текущее начало синхроимпульса вертикальной развертки, номер линии
029
uint32_t VS_sync_end;
// текущий конец синхроимпульса вертикальной развертки, номер линии
030
031
// tick, period, hsyne, hss, sw, nl, vss, vse
032
const
struct
tv_screen tv60 = { 7, 4592, 340, 837, 480, 302, 253, 261};
033
const
struct
tv_screen tv64 = { 6, 4608, 397, 981, 512, 302, 253, 261};
034
035
byte
buf[SCR_BUFFER_WIDTH*NUM_SCAN_LINES];
// 65*240=15600 экранный буфер (ориентировочно 0x200008B0)
036
uint32_t* buf_BB = (uint32_t*)(((uint32_t)buf - 0x20000000)*32 + 0x22000000);
// псевдоним экр. буфера в bit banding (~0x22011600)
037
int
lineNumber = 0;
// текущий номер строки при сканировании видеопамяти
038
int
toHS = ph1;
// ячейка для запоминания состояния HS - сразу по прерыванию заносится в порт, а потом вычисляется значение для следующей строки
039
uint32_t lenLine;
// длина видимой части строки в байтах, зависит только от режима: 60 при 480 пикселях и 64 - при 512
040
int
deltaLine = 0;
// ячейка для хранения смещения строки для очередной строки растра
041
int
Xchar, Ychar;
// пиксельные координаты верхнего левого угла текущего знакоместа (куда выводим символ)
042
void
(*putChar)(unsigned
char
);
// текущая процедура вывода символа на экран
043
int
newX, newY;
// новые координаты при рисовании и перемещении
044
int
charWidth;
// 6 или 8 - текущая ширина символа в пикселях
045
046
inline
void
startHS() {
// начало импульса HS, переводится из высокого состояния в низкое
047
pin_sync = ph0;
048
}
049
050
inline
void
endHS() {
// конец импульса HS, остается низким во время кадровой синхронизации
051
pin_sync = toHS;
052
toHS = (lineNumber <= VS_sync_start) || (lineNumber >= VS_sync_end);
// импульс VS 262-275
053
}
054
055
inline
void
endScreen() {
// конец видимой строки экрана, пока ничего не делаем, но вдруг понадибится...
056
}
057
058
inline
void
startScreen() {
059
if
(lineNumber < NUM_SCAN_LINES) {
060
DMA1_BASE->CCR3 &= 0xfffe;
//|= 0;
061
DMA1_BASE->CMAR3 = (uint32)&buf[deltaLine];
062
DMA1_BASE->CNDTR3 = lenLine+1;
063
DMA1_BASE->CCR3 = 0x3091;
// 0x3093
064
SPI1_BASE->CR1 = 0xC2C8;
// 0xffbf; // 0x021C;
065
TIMER2_BASE->CCER = 0x0010;
// CC2 enable
066
}
067
lineNumber++;
068
deltaLine += SCR_BUFFER_WIDTH;
069
if
(lineNumber >= VS_num_lines) {
// 292 288 конец кадра
070
lineNumber = 0;
071
deltaLine = 0;
072
}
073
}
074
075
void
inline setPixel(
int
x,
int
y) {
076
buf_BB[x + y*SCR_BUFFER_WIDTH*8] = 1;
077
}
078
079
void
inline clearPixel(
int
x,
int
y) {
080
buf_BB[x + y*SCR_BUFFER_WIDTH*8] = 0;
081
}
082
083
void
putChar6x8(unsigned
char
ch) {
084
for
(
int
i = 0; i < 5; i++) {
085
byte
b = SmallFont6[(ch -
' '
)*5 + 4 + i];
086
for
(
int
j = 0; j < 8; j++) {
087
buf_BB[Xchar + (Ychar+j)*SCR_BUFFER_WIDTH*8] = b & 1;
088
b = b >> 1;
089
}
090
Xchar++;
091
}
092
for
(
int
j = 0; j < 8; j++)
093
clearPixel(Xchar, Ychar+j);
094
Xchar++;
095
}
096
097
void
putChar8x8(unsigned
char
ch) {
098
for
(
int
i = 0; i < 8; i++) {
099
buf[Xchar/8 + (Ychar + i)*SCR_BUFFER_WIDTH] = font_c[(ch -
' '
)*8 + i];
100
}
101
Xchar += 8;
102
}
103
104
void
scrollUp() {
105
memcpy(&buf[0], &buf[8*SCR_BUFFER_WIDTH], (NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH);
106
memset(&buf[(NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH], 0, 8*SCR_BUFFER_WIDTH);
107
Xchar = 0;
108
Ychar = (NUM_SCAN_LINES - 8);
109
}
110
111
void
chessField() {
112
for
(
int
i = 0; i < (SCR_BUFFER_WIDTH*NUM_SCAN_LINES); i++) {
113
int
L = i/SCR_BUFFER_WIDTH;
114
int
J = i%SCR_BUFFER_WIDTH;
115
int
L0 = L/16&1;
116
int
J0 = J/2&1;
117
buf[i] = 255*((L0+J0)&1);
118
}
119
for
(
int
i = 0; i < NUM_SCAN_LINES; i++)
if
(buf[i*SCR_BUFFER_WIDTH] == 0) buf[i*SCR_BUFFER_WIDTH] = 2;
else
buf[i*SCR_BUFFER_WIDTH] = 253;
//
120
}
121
122
void
setCharSize6x8() {
123
putChar = putChar6x8;
124
charWidth = 6;
125
}
126
127
void
setCharSize8x8() {
128
putChar = putChar8x8;
129
charWidth = 8;
130
}
131
132
void
setXY(uint32_t x, uint32_t y) {
133
Xchar = x;
134
Ychar = y;
135
}
136
137
void
screenInit(
const
struct
tv_screen &SCR) {
138
uint32_t HS_screen_end = SCR.screen_width*SCR.tick_pix + SCR.HS_screen_start;
139
lenLine = SCR.screen_width / 8;
140
for
(
int
i = 0; i < NUM_SCAN_LINES; i++) buf[i*SCR_BUFFER_WIDTH+lenLine] = 0;
// заполнение последнего байта в строке нулями - гашение луча
141
142
GPIOB_BASE->CRL = 0x33444444;
// пины PB7,PB6 - выход, остальные - вход (не исп.)
143
GPIOB_BASE->CRH = 0x44444433;
// пины PB9-PB8 - выход, остальные - вход (не исп.)
144
GPIOA_BASE->CRL = 0xbb4444b4;
// пины MOSI(pa7), MISO(pa6), SCK(pa5), T2C2(PA1) - выход таймера
145
146
RCC_BASE->AHBENR |= 0x00000001;
// включение тактового сигнала DMA
147
RCC_BASE->APB2ENR |= (1 << 12);
// включение тактового сигнала SPI
148
DMA1_BASE->CPAR3 = 0x4001300C;
149
DMA1_BASE->CMAR3 = (uint32)buf;
150
DMA1_BASE->CNDTR3 = 13;
151
SPI1_BASE->CR1 = 0xC288;
// 0xffbf; // 0x021C;
152
SPI1_BASE->CR2 = 0x0082;
// 0x0082
153
DMA1_BASE->CCR3 = 0x3090;
// 0x3092
154
155
Timer4.pause();
// while we configure
156
delayMicroseconds(50);
157
158
VS_num_lines = SCR.VS_num_lines;
159
VS_sync_start = SCR.VS_sync_start;
160
VS_sync_end = SCR.VS_sync_end;
161
162
Timer4.setPrescaleFactor(1);
// Full speed
163
Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
164
Timer4.setChannel2Mode(TIMER_OUTPUTCOMPARE);
165
Timer4.setChannel3Mode(TIMER_OUTPUTCOMPARE);
166
Timer4.setChannel4Mode(TIMER_OUTPUTCOMPARE);
167
Timer4.setOverflow(SCR.HS_period - 1);
// 4591 : 63.7 ms, для делителя 7 оптимально 4592-1
168
169
Timer4.setCompare1(1);
// 1 - точка отсчета, условный 0, - начало импульса вертикальной синхронизации
170
Timer4.attachCompare1Interrupt(startHS);
// начало HS
171
Timer4.setCompare2(SCR.HS_syn_end);
// 339 - конец импульса синхронизации 4.7 мкс
172
Timer4.attachCompare2Interrupt(endHS);
// конец HS
173
Timer4.setCompare3(SCR.HS_screen_start);
// 831 - начало видимой части экрана 11.53 мс
174
Timer4.attachCompare3Interrupt(startScreen);
// начало видимой строки
175
Timer4.setCompare4(HS_screen_end);
// =4191 - примерная точка конца видимой части экрана 58.17 мкс
176
Timer4.attachCompare4Interrupt(endScreen);
177
178
Timer4.setCount(0);
// Ready...
179
Timer4.resume();
// Go!
180
181
TIMER2_BASE->PSC = 0;
// prescaler
182
TIMER2_BASE->ARR = SCR.tick_pix - 1;
// 6=7-1, где 7 - количество тиков (72МГц) на пиксель
183
TIMER2_BASE->CCR2 = SCR.tick_pix/2 - 1;
// 2
184
TIMER2_BASE->CCER = 0x0010;
// CC2 enable
185
delayMicroseconds(40);
186
}
187
188
void
setScreenMode(
int
mode) {
189
if
(mode == SCREEN_MODE_480) screenInit(tv60);
190
else
screenInit(tv64);
191
}
192
193
void
printCoord(
int
x,
int
y) {
194
Serial
.print(
'('
);
195
Serial
.print(x);
196
Serial
.print(
','
);
197
Serial
.print(y);
198
Serial
.println(
')'
);
199
}
200
201
void
lineTo(uint32_t x1, uint32_t y1) {
202
int
dx = (
int
)x1 - Xchar;
203
int
deltax = abs(dx);
204
int
dy = (
int
)y1 - Ychar;
205
int
deltay = abs(dy);
206
int
error = 0;
207
int
y = Ychar;
208
if
(dy > 0) dy = 1;
209
if
(dy < 0) dy = -1;
210
int
x = Xchar;
211
if
(dx > 0) dx = 1;
212
if
(dx < 0) dx = -1;
213
if
(deltax > deltay) {
214
int
deltaerr = deltay;
215
for
(
int
i = 0; i <= deltax; i++) {
216
setPixel(x,y);
217
error += deltaerr;
218
if
(2 * error >= deltax) {
219
y += dy;
220
error -= deltax;
221
}
222
x += dx;
223
}
224
}
else
{
225
int
deltaerr = deltax;
226
for
(
int
i = 0; i <= deltay; i++) {
227
setPixel(x,y);
228
error += deltaerr;
229
if
(2 * error >= deltay) {
230
x += dx;
231
error -= deltay;
232
}
233
y += dy;
234
}
235
}
236
Xchar = x1;
237
Ychar = y1;
238
}
239
240
void
nextLine() {
// перевод строки
241
Xchar = 0;
242
Ychar += 8;
243
if
(Ychar > (NUM_SCAN_LINES-8)) {
244
scrollUp();
245
}
246
}
247
248
void
printChar(unsigned
char
ch) {
249
static
int
mode = 0;
// 0-обычный, 1-введен ']', 2-введено "]~", 3-линия, ввод X, 4-линии, ввод Y, 5-6-moveTo, 9-пропускаем CR
250
switch
(mode) {
251
case
0:
// режим ввода однобайтных символов
252
case
9:
// то же самое, но пропустить CR
253
if
(ch <
' '
) {
// подблок однобайтных управляющих символов
254
if
(ch == 13) {
// обработка CR
255
if
(mode == 0) nextLine();
256
}
257
}
else
{
// ch >= ' ' подблок обычных символов
258
if
(ch == 127) {
// <BackSpace
259
if
(Xchar >= charWidth)
260
Xchar -= charWidth;
261
else
262
Xchar = 0;
263
}
else
{
// все обычные символы (32-126), включая начало упр.посл.
264
if
(ch ==
']'
) {
265
mode = 1;
// начало управляющей последовательности
266
}
else
{
// все обычные символы
267
if
(Xchar > (lenLine*8 - charWidth)) {
268
nextLine();
269
}
270
/*if(ch != 0)*/
putChar(ch);
271
}
272
}
273
}
274
if
(mode == 9) mode = 0;
275
break
;
276
case
1:
277
if
(ch ==
'~'
) mode = 2;
278
else
{
279
putChar(
']'
);
280
mode = 0;
281
}
282
break
;
283
case
2:
284
switch
(ch) {
285
case
'4'
: setScreenMode(SCREEN_MODE_480); mode = 9;
286
break
;
287
case
'5'
: setScreenMode(SCREEN_MODE_512); mode = 9;
288
break
;
289
case
'6'
: setCharSize6x8(); mode = 9;
290
break
;
291
case
'8'
: setCharSize8x8(); mode = 9;
292
break
;
293
case
'C'
: memset(buf, 0, SCR_BUFFER_WIDTH*NUM_SCAN_LINES); Xchar = 0; Ychar = 0; mode = 9;
294
break
;
295
case
'L'
: newX = 0; mode = 3;
296
break
;
297
case
'M'
: newX = 0; mode = 5;
298
break
;
299
default
:
300
putChar(
']'
);
301
putChar(
'~'
);
302
mode = 0;
303
}
304
break
;
305
case
3:
// линия, ввод X
306
if
((ch >=
'0'
) && (ch <=
'9'
)) newX = newX*10 + (ch -
'0'
);
307
else
308
if
(ch ==
'x'
) {
309
newY = 0;
310
mode = 4;
311
}
else
mode = 0;
312
break
;
313
case
4:
// линия, ввод Y
314
if
((ch >=
'0'
) && (ch <=
'9'
)) newY = newY*10 + (ch -
'0'
);
315
else
316
if
(ch ==
'$'
) {
317
if
(newX >= lenLine*8) newX = lenLine*8-1;
318
if
(newY >= NUM_SCAN_LINES) newY = NUM_SCAN_LINES-1;
319
lineTo(newX, newY);
320
Xchar = newX;
321
Ychar = newY;
322
mode = 9;
323
}
else
mode = 0;
324
break
;
325
case
5:
// перемещение, ввод X
326
if
((ch >=
'0'
) && (ch <=
'9'
)) newX = newX*10 + (ch -
'0'
);
327
else
328
if
(ch ==
'x'
) {
329
newY = 0;
330
mode = 6;
331
}
else
mode = 0;
332
break
;
333
case
6:
// перемещение, ввод Y
334
if
((ch >=
'0'
) && (ch <=
'9'
)) newY = newY*10 + (ch -
'0'
);
335
else
336
if
(ch ==
'$'
) {
337
if
(newX >= lenLine*8) newX = lenLine*8-1;
338
if
(newY >= NUM_SCAN_LINES) newY = NUM_SCAN_LINES-1;
339
Xchar = newX;
340
Ychar = newY;
341
mode = 9;
342
}
else
mode = 0;
343
break
;
344
}
345
}
И демонстрационный код на Меге:
test.ino
01
HardwareSerial * S = &Serial3;
02
03
void
sendSeq() {
04
S->println(
"test"
);
05
S->print(
"]~4"
);
06
S->print(
"]~C]~M200x100$]~8H e l l o !]~M160x140$]~6Serial Terminal Display Test]~M140x80$]~L340x80$]~L340x160$]~L140x160$]~L140x80$"
);
07
Serial
.println(
"OK!"
);
08
delay(4000);
09
10
S->print(
"]~C"
);
11
12
S->print(
"]~C"
);
13
for
(
int
i = 0; i < 128; i++) {
14
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
15
}
16
delay(4000);
17
S->print(
"]~5"
);
18
delay(4000);
19
for
(
int
i = 0; i < 128; i++) {
20
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
21
}
22
delay(4000);
23
S->print(
"]~8"
);
24
for
(
int
i = 0; i < 128; i++) {
25
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
26
}
27
delay(4000);
28
S->print(
"]~4"
);
29
delay(4000);
30
for
(
int
i = 0; i < 128; i++) {
31
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
32
}
33
delay(4000);
34
S->print(
"]~5"
);
35
delay(4000);
36
S->print(
"]~C"
);
37
for
(
int
i = 0; i < 1024; i++) {
38
S->print(
"]~L"
);
39
S->print(random(512));
40
S->print(
"x"
);
41
S->print(random(240));
42
S->print(
"$"
);
43
}
44
S->print(
"]~M228x108$ "
);
45
S->print(
"]~M228x116$ E N D "
);
46
S->print(
"]~M228x124$ "
);
47
delay(4000);
48
}
49
50
void
setup
() {
51
S->begin(9600);
52
Serial
.begin(115200);
53
sendSeq();
54
}
55
56
void
loop
() {
57
}
Выход TX3 Меги нужно подключить ко входу RX1 stm32.
Напоминаю, что:
кириллица пока не поддерживается,
борьба с помехами пока не ведется.
Управляющие коды описаны в screen.h. Можно подключить к stm32 вместо Меги ПК через USB-UART и передавать команды и строки текста прямо из монитора порта.
Похожий проект "VGA на Arduino Due": https://github.com/stimmer/DueVGA/
Да, сходство есть.
Но мне хотелось:
1. Не менее 80 символов в строке (а в указанном проекте - до 53).
2. Обойтись контроллером, который почти на порядок дешевле.
При этих условиях единственный вариант - отказаться от цвета.
Но я сейчас продумываю вариант, при котором можно будет задавать цвет каждой строки целиком (из 7-255 цветов). Вот только думаю, может ли такое когда-нибудь кому-нибудь понадобиться. Тем более, что такой вариант однозначно предполагает переход с композитного сигнала на VGA.
Похожий проект "VGA на Arduino Due": https://github.com/stimmer/DueVGA/
Схемы здесь (для VGA и TV): http://stimmer.github.io/DueVGA/
http://stimmer.github.io/DueVGA/breadboard.html
http://stimmer.github.io/DueVGA/tvout.html
Да, посмотрел дэйташит на SAM8, там, в отличие от stm32, для SPI можно использовать практически любой коэффициент деления, тогда как для stm32 - только степени двойки. Наверное поэтому для sym32 и нет аналогов. Но я обошел это при помощи SPI slave.
А так - конечно, Due выглядит более многообещающим вариантом по сравнению с stm32f103 из-за впятеро большего объема памяти, на 17% более высокой тактовой частоты и большей свободы в выборе пиксельной частоты. Но, с другой стороны - неудобный формфактор и высокая цена.
PS. Естественно, проект не претендует на популярность, т.к. первый вопрос - "Зачем?". Но, все-таки, хотелось бы выслушать мнения по двум вопросам:
1. Какой интерфейс предпочтительнее: композитный TV-сигнал или VGA?
2. Имеет ли какой-то смысл предусмотреть возможность выводить каждую строку растра своим цветом?
Сделал поддержку кириллицы.
Поддерживаются 4 кодировки: UTF-8, KOI8R, CP-1251 (Windows), CP-866 (Альтернативная ГОСТ). По умолчанию включена UTF-8, но управляющими последовательностями их можно переключать.
В дальнейшем планируется сделать настройки по умолчанию при помощи dip-переключателя, тобы устройство могло работать в любом из поддерживаемых режимов совместно с устройством, которое ничего не знает об управляющих последовательностях.
Но, пожалуй, данный вариант устройства приобрел более или менее законченные очертания - дальнейшая работа предполагается в расчете на VGA разъем и с ограниченной поддержкой цвета.
Поэтому публикую его полностью.
Схема:
Основной файл:
001
#include <SPI.h>
002
#include "screen.h"
003
004
void
printStr(
const
char
* ch) {
005
while
(*ch) {
/*Serial.println((byte)(*ch));*/
printChar((unsigned
char
)*ch++);
/*ch++;*/
}
006
}
007
008
void
printCharSet(
int
x,
int
y, unsigned
char
b,
const
char
* ch) {
009
setXYchar(x,y);
010
printStr(ch);
011
int
jj = b > 127 ? 4 : 8;
012
for
(
int
j = 0; j < jj; j++) {
013
setXYchar(x,y+(j+1)*8);
014
for
(
int
i = 0; i < 16; i++) {
015
if
(b > 127) printChar(b);
016
printChar((unsigned
char
)(128 + j*16 + i));
017
}
018
}
019
}
020
021
void
setup
() {
022
Serial
.begin(115200);
// Ignored by Maple. But needed by boards using hardware serial via a USB to Serial adaptor ]'
023
while
(!
Serial
) ;
024
//Serial.println("start");
025
uint32_t t0 = micros();
026
scrollUp();
027
028
uint32_t t1 = micros();
029
chessField();
030
031
uint32_t t2 = micros();
032
setXYpix(0, 0);
033
lineTo(239, 239);
034
035
uint32_t t3 = micros();
036
setXYchar(0, 2);
037
setCharSize(CHAR_SIZE_6x8);
038
for
(
int
i = 0; i < 60; i++) printChar(
' '
+ i + 1);
039
040
uint32_t t4 = micros();
041
setXYchar(0, 12);
042
setCharSize(CHAR_SIZE_8x8);
043
for
(
int
i = 0; i < 60; i++) printChar(
' '
+ i + 1);
044
045
uint32_t t5 = micros();
046
047
setXYchar(0, 22);
048
for
(
int
i = 0; i < 60; i++) printChar(
' '
+ i + 1);
049
setXYchar(0, 30);
050
for
(
int
i = 59; i < 93; i++) printChar(
' '
+ i + 1);
051
052
setCharSize(CHAR_SIZE_6x8);
053
setXYchar(0, 40);
054
for
(
int
i = 0; i < 60; i++) printChar(
' '
+ i + 1);
055
setXYchar(0, 48);
056
for
(
int
i = 59; i < 93; i++) printChar(
' '
+ i + 1);
057
058
Serial1.begin(9600);
059
delay(1);
060
setScreenMode(SCREEN_MODE_480);
061
062
const
char
*cyr_1 =
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяЃѓЄєІіЇїЎўҐґ§°±µ0123456789"
;
063
064
setXYchar(0, 58);
065
for
(
int
i = 0; i < 184-10; i++) {
// 10 однобайтных цифр
066
printChar(cyr_1[i]);
067
}
068
069
setCharSize(CHAR_SIZE_8x8);
070
setXYchar(0, 76);
071
for
(
int
i = 0; i < 184-10; i++) {
072
printChar(cyr_1[i]);
073
}
074
075
setXYchar(0, 94);
076
printStr(
"Кодировка UTF-8. Российская Федерация, Україна, Рэспубліка Беларусь"
);
077
078
079
printCharSet(24, 114, 0xD0,
"UTF-8 D0"
);
080
printCharSet(176, 114, 0xD1,
"UTF-8 D1"
);
081
printCharSet(328, 114, 0xC2,
"UTF-8 C2"
);
082
// printCharSet(24, 164, 0xC2, "UTF-8 C2");
083
setCodePage(CP_1251);
084
printCharSet(176, 164, 2,
"CP-1251"
);
085
setCodePage(CP_866);
086
printCharSet(328, 164, 2,
"CP-866"
);
087
setCodePage(CP_KOI8);
088
printCharSet(24, 164, 2,
"CP-KOI8R"
);
089
090
Serial
.print(
"Scroll Up "
);
091
Serial
.println(t1-t0);
092
Serial
.print(
"Chess Field "
);
093
Serial
.println(t2-t1);
094
Serial
.print(
"Line 240 pix."
);
095
Serial
.println(t3-t2);
096
Serial
.print(
"60 chars 6x8 "
);
097
Serial
.println(t4-t3);
098
Serial
.print(
"60 chars 8x8 "
);
099
Serial
.println(t5-t4);
100
101
setCharSize(CHAR_SIZE_8x8);
102
103
setXYpix(240+45, 120);
104
lineTo(240, 120+85);
105
lineTo(240-200, 120);
106
lineTo(240, 120-100);
107
lineTo(240, 120);
108
lineTo(240+45, 120);
109
110
setXYchar(0, 232);
111
pinMode(LED_BUILTIN, OUTPUT);
112
113
// This gets rid of the majority of the interrupt artifacts;
114
// a SysTick.end() is required as well
115
Serial
.end();
116
117
}
118
119
// #define DEBUG
120
void
loop
() {
121
static
int
ledState = LOW;
// blink
122
static
unsigned
long
previousMillis = 0;
123
static
long
interval = 20;
124
unsigned
long
currentMillis = millis();
125
126
if
(currentMillis - previousMillis >= interval) {
127
previousMillis = currentMillis;
128
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
129
interval = 20 + digitalRead(LED_BUILTIN)*980;
130
}
131
if
(Serial1.available()) {
// обработка ввода
132
unsigned
char
ch = Serial1.read();
133
#ifdef DEBUG
134
if
(ch >=
' '
) {
135
Serial
.print((
char
)ch);
136
}
else
{
137
Serial
.print(
'^'
);
138
Serial
.print((
char
)(ch +
'A'
- 1));
139
}
140
Serial
.print(
" 0x"
);
141
Serial
.println((
byte
)ch,HEX);
142
#endif
143
printChar(ch);
144
}
145
}
Заголовочный файл библиотеки screen.h:
01
#ifndef SCREEN_H
02
#define SCREEN_H
03
04
// Библиотечка использует stm32f103 для формирования полного TV-сигнала,
05
// позволяет выводить на экран текст и рисовать линии.
06
// Возможности:
07
// Позволяет установить один из двух видеорежимов: 480х240 или 512х240 пикселей,
08
// Позволяет выводить текст фонтами размером 6х8 и 8х8 (жирный) пикселей, могут присутствовать на экране одновременно,
09
// Позволяет рисовать линии при помощи управляющих последовательностей,
10
// Автоматический перенос текста по достижении правого края экрана
11
// Автоматический скроллинг по достижении нижнего края экрана
12
// Поддерживаются слежующие управляющие последовательности
13
// ]~4 - переключение в режим 480 пикселей
14
// ]~5 - переключение в режим 512 пикселей
15
// ]~6 - переключение в режим узкого шрифта 6х8
16
// ]~8 - переключение в режим широкого шрифта 8х8
17
// ]~C- очистка экрана
18
// ]~LXXXxYYY$ - рисование линии из текущей точки в указанную
19
// ]~MXXXxYYY$ - перемещение текущей позиции рисования линии в указанную точку
20
// ]~PXXXxYYY$ - перемещение текущей позиции печати текста в указанную точку
21
// где XXX и YYY - десятичная запись одно-, двух- или трехзначных координат.
22
// ]~U - переключение в кодировку UTF-8
23
// ]~1 - переключение в кодировку 1251
24
// ]~A - переключение в кодировку 866 (альтернативная ГОСТ)
25
// ]~K - переключение в кодировку KOI-8
26
// управляющая последовательность может (но не обязана) заканчиваться символом перевода строки, который в этом случае опускается,
27
// в тексте символ 0x13 обрабатывается как конец строки, другие однобайтовые управляющие символы пока не поддерживаются.
28
//
29
// !!! пока не предпринимались попытки борьбы с помехами на экране !!!
30
31
#define SCREEN_MODE_480 0 // режим дисплея разрешением 480х240
32
#define SCREEN_MODE_512 1 // режим дисплея разрешением 512х240
33
#define CHAR_SIZE_6x8 0 // режим узких символов 6х8
34
#define CHAR_SIZE_8x8 1 // режим широких символов 8х8
35
#define CP_UTF8 0 // режим кодировки UTF-8
36
#define CP_1251 1 // режим кодировки CP-1251
37
#define CP_866 2 // режим кодировки CP-866 (Альтернативная ГОСТ)
38
#define CP_KOI8 3 // режим кодировки KOI8R
39
40
extern
void
scrollUp();
// пролистывание экрана на одну строку (8 пикселей) вверх и очистка последней строки
41
extern
void
chessField();
// рисует на экране "шахматное" поле с "квадратиком" 16х16 пикселей
42
extern
void
setScreenMode(
int
mode);
// установка одного из двух режимов 480х240 или 512х240 пикселей
43
extern
void
setCharSize(
int
size);
// выбор фонта 6х8 или 8х8 пикселей
44
extern
void
setCodePage(
int
page);
// выбор кодовой страницы
45
extern
void
setXYchar(uint32_t x, uint32_t y);
// устанавливает текущую позицию вывода символа
46
extern
void
setXYpix(uint32_t x, uint32_t y);
// устанавливает текущую позицию вывода линии
47
extern
void
printChar(unsigned
char
ch);
// вывод символа в текущую позицию
48
extern
void
lineTo(uint32_t x1, uint32_t y1);
// рисует линию из текущей позиции в указанную (вместо moveTo(); следует использовать setXY(); )
49
50
#endif
файл библиотеки screen.cpp:
001
#define NUM_SCAN_LINES 240 // количество линий растра экрана (видимых)
002
#define SCR_BUFFER_WIDTH 65 // длина строки видеобуфера в байтах (64 байта = 512 пикселей макс. + 1 байт-бордюр, обеспечивающий гашение луча)
003
004
#include <Arduino.h> // SCREEN_WIDTH*TICK_PIX + HS_SCREEN_START
005
#include <SPI.h>
006
#include "a_Small_Rus.c"
007
#include "font_c.c"
008
009
#define ph0 0 //LOW
010
#define ph1 1 //HIGH
011
012
#define pin_sync (*((volatile unsigned long *) 0x422181A4 )) // PB9
013
014
#include "screen.h"
015
016
struct
tv_screen {
// HS отсчитывается от начала синхроимпульса, VS - от начала первой видимой строки экрана
017
uint32_t tick_pix;
// 6 или 7 тактов (72 МГц) на пиксель, пиксельная частота =72000000/tick_pix
018
uint32_t HS_period;
// 63.5-64 мс, 4572-4608 тактов, такты кратны TICK_PIX, для tick_pix=7 - HS_period=4592, для tick_pix=6 - HS_period=4608
019
uint32_t HS_syn_end;
// 4.7 мкс - конец импульса синхронизации, в тактах
020
uint32_t HS_screen_start;
// 11.61 мкс - начало видимой части экрана (по ГОСТ 10.5 мкс), в тактах
021
uint32_t screen_width;
// 480 или 512 - ширина экрана (3072 или 3360 тактов), в пикселях
022
uint32_t VS_num_lines;
// полное количество линий развертки в кадре (288-312)
023
uint32_t VS_sync_start;
// первая строка импульса VS
024
uint32_t VS_sync_end;
// последняя строка импульса VS
025
};
026
027
uint32_t VS_num_lines;
// текущее количество линий вертикальной развертки
028
uint32_t VS_sync_start;
// текущее начало синхроимпульса вертикальной развертки, номер линии
029
uint32_t VS_sync_end;
// текущий конец синхроимпульса вертикальной развертки, номер линии
030
031
// tick, period, hsyne, hss, sw, nl, vss, vse
032
const
struct
tv_screen tv480 = { 7, 4592, 340, 837, 480, 302, 253, 261};
033
const
struct
tv_screen tv512 = { 6, 4608, 397, 981, 512, 302, 253, 261};
034
035
unsigned
char
recodeCharUTF(unsigned
char
ch);
// !!! предварительное объявление - потом убрать !!!
036
037
byte
buf[SCR_BUFFER_WIDTH*NUM_SCAN_LINES];
// 65*240=15600 экранный буфер (ориентировочно 0x200008B0)
038
uint32_t* buf_BB = (uint32_t*)(((uint32_t)buf - 0x20000000)*32 + 0x22000000);
// псевдоним экр. буфера в bit banding (~0x22011600)
039
int
lineNumber = 0;
// текущий номер строки при сканировании видеопамяти
040
int
toHS = ph1;
// ячейка для запоминания состояния HS - сразу по прерыванию заносится в порт, а потом вычисляется значение для следующей строки
041
uint32_t lenLine;
// длина видимой части строки в байтах, зависит только от режима: 60 при 480 пикселях и 64 - при 512
042
int
Xchar, Ychar;
// пиксельные координаты верхнего левого угла текущего знакоместа (куда выводим символ)
043
int
Xpix, Ypix;
// координаты для рисования линии
044
void
(*drawChar)(unsigned
char
);
// текущая процедура вывода символа на экран
045
unsigned
char
(*recodeChar)(unsigned
char
) = recodeCharUTF;
// текущая процедура перекодировки символа
046
int
charWidth;
// 6 или 8 - текущая ширина символа в пикселях
047
048
inline
void
startHS() {
// начало импульса HS, переводится из высокого состояния в низкое
049
pin_sync = ph0;
050
}
051
052
inline
void
endHS() {
// конец импульса HS, остается низким во время кадровой синхронизации
053
pin_sync = toHS;
054
toHS = (lineNumber <= VS_sync_start) || (lineNumber >= VS_sync_end);
// импульс VS 262-275
055
}
056
057
inline
void
endScreen() {
// конец видимой строки экрана, пока ничего не делаем, но вдруг понадибится...
058
}
059
060
inline
void
startScreen() {
061
static
int
deltaLine = 0;
// ячейка для хранения смещения строки для очередной строки растра
062
if
(lineNumber < NUM_SCAN_LINES) {
063
DMA1_BASE->CCR3 &= 0xfffe;
//|= 0;
064
DMA1_BASE->CMAR3 = (uint32)&buf[deltaLine];
065
DMA1_BASE->CNDTR3 = lenLine+1;
066
DMA1_BASE->CCR3 = 0x3091;
// 0x3093
067
SPI1_BASE->CR1 = 0xC2C8;
// 0xffbf; // 0x021C;
068
// TIMER2_BASE->CCER = 0x0010; // CC2 enable
069
}
070
lineNumber++;
071
deltaLine += SCR_BUFFER_WIDTH;
072
if
(lineNumber >= VS_num_lines) {
// 292 288 конец кадра
073
lineNumber = 0;
074
deltaLine = 0;
075
}
076
}
077
078
void
setXYchar(uint32_t x, uint32_t y) {
079
Xchar = x;
080
Ychar = y;
081
}
082
083
void
setXYpix(uint32_t x, uint32_t y) {
084
Xpix = x;
085
Ypix = y;
086
}
087
088
void
inline setPixel(
int
x,
int
y) {
089
buf_BB[x + y*SCR_BUFFER_WIDTH*8] = 1;
090
}
091
092
void
inline clearPixel(
int
x,
int
y) {
093
buf_BB[x + y*SCR_BUFFER_WIDTH*8] = 0;
094
}
095
096
void
scrollUp() {
097
memcpy(&buf[0], &buf[8*SCR_BUFFER_WIDTH], (NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH);
098
memset(&buf[(NUM_SCAN_LINES - 8)*SCR_BUFFER_WIDTH], 0, 8*SCR_BUFFER_WIDTH);
099
setXYchar(0, NUM_SCAN_LINES - 8);
100
}
101
102
void
nextLine() {
// перевод строки
103
setXYchar(0, Ychar + 8);
104
if
(Ychar > (NUM_SCAN_LINES-8)) {
105
scrollUp();
106
}
107
}
108
109
void
drawChar6x8(unsigned
char
ch) {
110
if
(ch == 255)
return
;
// ничего не печатать (вероятно, 1-й байт многобайтового символа)
111
// Serial.print("ch: ");
112
// Serial.print(ch);
113
// Serial.print(", Xchar: ");
114
// Serial.print(Xchar);
115
// Serial.print(", Ychar: ");
116
// Serial.println(Ychar);
117
// Serial.print("ch:");
118
// Serial.print("ch:");
119
if
(Xchar > (lenLine*8 - charWidth)) {
120
nextLine();
121
}
122
for
(
int
i = 0; i < 5; i++) {
123
byte
b = SmallFont6[(ch
/*- ' '*/
)*5 + 4 + i];
124
for
(
int
j = 0; j < 8; j++) {
125
buf_BB[Xchar + (Ychar+j)*SCR_BUFFER_WIDTH*8] = b & 1;
126
b = b >> 1;
127
}
128
Xchar++;
129
}
130
for
(
int
j = 0; j < 8; j++)
131
// clearPixel(Xchar, Ychar+j);
132
buf_BB[Xchar + (Ychar+j)*SCR_BUFFER_WIDTH*8] = 0;
133
Xchar++;
134
}
135
136
void
drawChar8x8(unsigned
char
ch) {
137
if
(ch == 255)
return
;
// ничего не печатать (вероятно, 1-й байт многобайтового символа)
138
if
(Xchar > (lenLine*8 - charWidth)) {
139
nextLine();
140
}
141
for
(
int
i = 0; i < 8; i++) {
142
buf[Xchar/8 + (Ychar + i)*SCR_BUFFER_WIDTH] = font_c[(ch
/*- ' '*/
)*8 + i];
143
}
144
Xchar += 8;
145
}
146
147
const
unsigned
char
utf_D0[] = {
148
37, 141, 14, 143, 145, 51, 41, 147, 42, 14, 14, 72, 43, 101, 149, 14,
// .Ё.ЃЄSIЇJ.....Ў.
149
33, 95, 34, 96, 97, 37, 98, 99, 100, 101, 43, 102, 45, 40, 47, 103,
// АБВГДЕЖЗИЙКЛМНОП
150
48, 35, 52, 104, 105, 56, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
// РСТУФХЦЧШЩЪЫЬЭЮЯ
151
65, 116, 117, 118, 119, 69, 120, 121, 122, 123, 124, 125, 126, 127, 79, 128
// абвгдежзийклмноп
152
};
153
154
const
unsigned
char
utf_D1[] = {
155
80, 67, 129, 89, 130, 88, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
// рстуфхцчшщъыьэюя
156
69, 142, 14, 144, 146, 83, 73, 148, 74, 14, 14, 72, 124, 123, 150, 14
// .ё.ѓєsiїj.....ў.
157
};
158
159
const
unsigned
char
ansi1251[] = {
160
14, 143, 12, 144, 2, 14, 14, 14, 146, 14, 14, 28, 14, 43, 72, 14,
// .Ѓ,ѓ"...є..<.Кh.
161
14, 64, 7, 2, 2, 14, 13, 13, 0, 14, 14, 30, 14, 124, 72, 14,
// .`'...--...>.кh.
162
0, 149, 150, 42, 14, 151, 92, 153, 141, 14, 145, 14, 14, 0, 14, 147,
// ЎўJ.Ґ|§Ё.Є.. .Ї
163
154, 155, 41, 73, 152, 156, 14, 14, 142, 46, 146, 14, 74, 51, 83, 148,
// °±Iiґµ..ё№є.jSsї
164
33, 95, 34, 96, 97, 37, 98, 99, 100, 101, 43, 102, 45, 40, 47, 103,
// АБВГДЕЖЗИЙКЛМНОП
165
48, 35, 52, 104, 105, 56, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
// РСТУФХЦЧШЩЪЫЬЭЮЯ
166
65, 116, 117, 118, 119, 69, 120, 121, 122, 123, 124, 125, 126, 127, 79, 128,
// абвгдежзийклмноп
167
80, 67, 129, 89, 130, 88, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140
// рстуфхцчшщъыьэюя
168
};
169
170
const
unsigned
char
oem866[] = {
171
33, 95, 34, 96, 97, 37, 98, 99, 100, 101, 43, 102, 45, 40, 47, 103,
// АБВГДЕЖЗИЙКЛМНОП
172
48, 35, 52, 104, 105, 56, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
// РСТУФХЦЧШЩЪЫЬЭЮЯ
173
65, 116, 117, 118, 119, 69, 120, 121, 122, 123, 124, 125, 126, 127, 79, 128,
// абвгдежзийклмноп
174
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// псевдографика
175
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// псевдографика
176
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// псевдографика
177
80, 67, 129, 89, 130, 88, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
// рстуфхцчшщъыьэюя
178
141, 142, 145, 145, 147, 148, 149, 150, 154, 14, 14, 14, 46, 14, 14, 14
// ЁёЄєЇїЎў°...№...
179
};
180
181
const
unsigned
char
koi8r[] = {
182
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// ................
183
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 154, 14, 14, 14,
// .......... .°...
184
14, 14, 14, 142, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// ...ё............
185
14, 14, 14, 141, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
// ...Ё............
186
139, 65, 116, 131, 119, 69, 130, 118, 88, 122, 123, 124, 125, 126, 127, 79,
// юабцдефгхийклмно
187
128, 140, 80, 67, 129, 89, 120, 117, 137, 136, 121, 133, 138, 134, 132, 135,
// пярстужвьызшэщчъ
188
114, 33, 95, 106, 97, 37, 105, 96, 56, 100, 101, 43, 102, 45, 40, 47,
// ЮАБЦДЕФГХИЙКЛМНО
189
103, 115, 48, 35, 52, 104, 98, 34, 112, 111, 99, 108, 113, 109, 107, 110
// ПЯРСТУЖВЬЫЗШЭЩЧЪ
190
};
191
192
unsigned
char
recodeChar1251(unsigned
char
ch) {
193
return
ansi1251[ch-128];
194
}
195
196
unsigned
char
recodeChar866(unsigned
char
ch) {
197
return
oem866[ch-128];
198
}
199
200
unsigned
char
recodeCharKOI8(unsigned
char
ch) {
201
return
koi8r[ch - 128];
202
}
203
204
unsigned
char
recodeCharUTF(unsigned
char
ch) {
205
static
byte
firstByte = 0;
206
if
(firstByte == 0) {
207
firstByte = ch;
208
return
255;
209
}
else
{
210
switch
(firstByte) {
211
case
(unsigned
char
)0xD0: firstByte = 0;
212
if
(ch < 0xC0) {
return
utf_D0[ch - 128];
213
}
else
{
return
14; }
214
case
(unsigned
char
)0xD1: firstByte = 0;
215
if
(ch < 0xA0) {
return
utf_D1[ch - 128];
216
}
else
{
return
14; }
217
case
(unsigned
char
)0xD2: firstByte = 0;
218
if
(ch == 144) {
return
151;
// Ґ
219
}
else
if
(ch == 145) {
return
152;
// ґ
220
}
else
{
return
14; }
221
break
;
222
case
(unsigned
char
)0xC2: firstByte = 0;
223
if
(ch == 167) {
return
153;
// §
224
}
else
if
(ch == 176) {
return
154;
// °
225
}
else
if
(ch == 177) {
return
155;
// ±
226
}
else
if
(ch == 181) {
return
156;
// µ
227
}
else
{
return
14; }
228
break
;
229
default
: firstByte = 0;
return
14;
break
;
230
}
231
}
232
}
233
234
void
setCodePage(
int
page) {
// выбор кодовой страницы
235
switch
(page) {
236
case
(CP_UTF8): recodeChar = recodeCharUTF;
break
;
237
case
(CP_1251): recodeChar = recodeChar1251;
break
;
238
case
(CP_866): recodeChar = recodeChar866;
break
;
239
case
(CP_KOI8): recodeChar = recodeCharKOI8;
break
;
240
}
241
}
242
243
void
putChar(unsigned
char
ch) {
244
if
(ch <= 126) drawChar(ch - 32);
245
else
drawChar(recodeChar(ch));
246
}
247
248
void
chessField() {
249
for
(
int
i = 0; i < (SCR_BUFFER_WIDTH*NUM_SCAN_LINES); i++) {
250
int
L = i/SCR_BUFFER_WIDTH;
251
int
J = i%SCR_BUFFER_WIDTH;
252
int
L0 = L/16&1;
253
int
J0 = J/2&1;
254
buf[i] = 255*((L0+J0)&1);
255
}
256
for
(
int
i = 0; i < NUM_SCAN_LINES; i++)
if
(buf[i*SCR_BUFFER_WIDTH] == 0) buf[i*SCR_BUFFER_WIDTH] = 2;
else
buf[i*SCR_BUFFER_WIDTH] = 253;
//
257
}
258
259
void
setCharSize(
int
size) {
260
switch
(size) {
261
case
(CHAR_SIZE_6x8): {
262
drawChar = drawChar6x8;
263
charWidth = 6;
264
break
;
265
}
266
case
(CHAR_SIZE_8x8): {
267
drawChar = drawChar8x8;
268
charWidth = 8;
269
break
;
270
}
271
}
272
}
273
274
void
screenInit(
const
struct
tv_screen &SCR) {
275
// Serial.println("scrInit");
276
static
bool
first =
true
;
277
noInterrupts();
278
// while(!(SPI1_BASE->SR) | 1);
279
// while((!(SPI1_BASE->SR & 2)) && !first); // TXE (Transmit buffer Empty)
280
// while(SPI1_BASE->SR & 0x0080); // BSY
281
// int rg = SPI1_BASE->SR;
282
uint32_t HS_screen_end = SCR.screen_width*SCR.tick_pix + SCR.HS_screen_start;
283
lenLine = SCR.screen_width / 8;
284
for
(
int
i = 0; i < NUM_SCAN_LINES; i++) buf[i*SCR_BUFFER_WIDTH+lenLine] = 0;
// заполнение последнего байта в строке нулями - гашение луча
285
286
if
(first) {
287
recodeChar = recodeCharUTF;
288
GPIOB_BASE->CRL = 0x33444444;
// пины PB7,PB6 - выход, остальные - вход (не исп.)
289
GPIOB_BASE->CRH = 0x44444433;
// пины PB9-PB8 - выход, остальные - вход (не исп.)
290
GPIOA_BASE->CRL = 0xbb4444b4;
// пины MOSI(pa7), MISO(pa6), SCK(pa5), T2C2(PA1) - выход таймера
291
292
RCC_BASE->AHBENR |= 0x00000001;
// включение тактового сигнала DMA
293
RCC_BASE->APB2ENR |= (1 << 12);
// включение тактового сигнала SPI
294
295
// SPI1_BASE->CR1 &= ~0x0040; // выключаем SPI
296
// DMA1_BASE->CCR3 &= ~0x0001; // выключаем DMA
297
298
DMA1_BASE->CPAR3 = 0x4001300C;
299
DMA1_BASE->CMAR3 = (uint32)buf;
300
DMA1_BASE->CNDTR3 = 13;
301
SPI1_BASE->CR1 = 0xC288;
// 0xffbf; // 0x021C;
302
SPI1_BASE->CR2 = 0x0082;
// 0x0082
303
DMA1_BASE->CCR3 = 0x3090;
// 0x3092
304
}
305
Timer4.pause();
// while we configure
306
delayMicroseconds(50);
307
308
VS_num_lines = SCR.VS_num_lines;
309
VS_sync_start = SCR.VS_sync_start;
310
VS_sync_end = SCR.VS_sync_end;
311
312
if
(first){
313
Timer4.setPrescaleFactor(1);
// Full speed
314
Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
315
Timer4.setChannel2Mode(TIMER_OUTPUTCOMPARE);
316
Timer4.setChannel3Mode(TIMER_OUTPUTCOMPARE);
317
Timer4.setChannel4Mode(TIMER_OUTPUTCOMPARE);
318
Timer4.setCompare1(1);
// 1 - точка отсчета, условный 0, - начало импульса вертикальной синхронизации
319
Timer4.attachCompare1Interrupt(startHS);
// начало HS
320
Timer4.attachCompare2Interrupt(endHS);
// конец HS
321
Timer4.attachCompare3Interrupt(startScreen);
// начало видимой строки
322
Timer4.attachCompare4Interrupt(endScreen);
323
}
324
Timer4.setOverflow(SCR.HS_period - 1);
// 4591 : 63.7 ms, для делителя 7 оптимально 4592-1
325
Timer4.setCompare2(SCR.HS_syn_end);
// 339 - конец импульса синхронизации 4.7 мкс
326
Timer4.setCompare3(SCR.HS_screen_start);
// 831 - начало видимой части экрана 11.53 мс
327
Timer4.setCompare4(HS_screen_end);
// =4191 - примерная точка конца видимой части экрана 58.17 мкс
328
329
Timer4.setCount(0);
// Ready...
330
Timer4.resume();
// Go!
331
332
TIMER2_BASE->CR1 &= ~1;
// выключаем
333
if
(first) {
334
TIMER2_BASE->PSC = 0;
// prescaler
335
TIMER2_BASE->CCER = 0x0010;
// CC2 enable
336
first =
false
;
337
}
338
TIMER2_BASE->ARR = SCR.tick_pix - 1;
// 6=7-1, где 7 - количество тиков (72МГц) на пиксель
339
TIMER2_BASE->CCR2 = SCR.tick_pix/2 - 1;
// 2
340
TIMER2_BASE->CR1 |= 1;
// выключаем
341
interrupts();
342
delayMicroseconds(40);
343
// Serial.println(rg, HEX);
344
}
345
346
void
setScreenMode(
int
mode) {
347
if
(mode == SCREEN_MODE_480) screenInit(tv480);
348
else
screenInit(tv512);
349
}
350
351
void
printCoord(
int
x,
int
y) {
352
Serial
.print(
'('
);
353
Serial
.print(x);
354
Serial
.print(
','
);
355
Serial
.print(y);
356
Serial
.println(
')'
);
357
}
358
359
void
lineTo(uint32_t x1, uint32_t y1) {
360
int
dx = (
int
)x1 - Xpix;
361
int
deltax = abs(dx);
362
int
dy = (
int
)y1 - Ypix;
363
int
deltay = abs(dy);
364
int
error = 0;
365
int
y = Ypix;
366
if
(dy > 0) dy = 1;
367
if
(dy < 0) dy = -1;
368
int
x = Xpix;
369
if
(dx > 0) dx = 1;
370
if
(dx < 0) dx = -1;
371
if
(deltax > deltay) {
372
int
deltaerr = deltay;
373
for
(
int
i = 0; i <= deltax; i++) {
374
setPixel(x,y);
375
error += deltaerr;
376
if
(2 * error >= deltax) {
377
y += dy;
378
error -= deltax;
379
}
380
x += dx;
381
}
382
}
else
{
383
int
deltaerr = deltax;
384
for
(
int
i = 0; i <= deltay; i++) {
385
setPixel(x,y);
386
error += deltaerr;
387
if
(2 * error >= deltay) {
388
x += dx;
389
error -= deltay;
390
}
391
y += dy;
392
}
393
}
394
setXYpix(x1, y1);
395
}
396
397
void
printChar(unsigned
char
ch) {
398
/* Serial.print("print ");
399
if(ch >= ' ') {
400
Serial.print((char)ch);
401
} else {
402
Serial.print('^');
403
Serial.print((char)(ch + 'A' - 1));
404
}
405
Serial.print(" 0x");
406
Serial.println((byte)ch,HEX);
407
*/
408
static
int
mode = 0;
// 0-обычный, 1-введен ']', 2-введено "]~", 3-линия, ввод X, 4-линии, ввод Y, 5-6-moveTo, 7-8-textTo, 9-пропускаем CR
409
static
int
newX, newY;
// новые координаты при рисовании и перемещении
410
switch
(mode) {
411
case
0:
// режим ввода символов
412
case
9:
// то же самое, но пропустить CR (после ввода управляющих символов)
413
if
(ch <
' '
) {
// подблок однобайтных управляющих символов
414
if
(ch == 13) {
// обработка CR
415
if
(mode == 0) nextLine();
416
}
417
}
else
{
// ch >= ' ' подблок обычных символов
418
if
(ch == 127) {
// <BackSpace
419
if
(Xchar >= charWidth)
420
Xchar -= charWidth;
421
else
422
Xchar = 0;
423
}
else
{
// все обычные символы (32-126, 128-255), включая начало упр.посл.
424
if
(ch ==
']'
) {
425
mode = 1;
// начало управляющей последовательности
426
}
else
{
// все обычные символы
427
putChar(ch);
428
}
429
}
430
}
431
if
(mode == 9) mode = 0;
432
break
;
433
case
1:
// перед этим был введен ]
434
if
(ch ==
'~'
) mode = 2;
435
else
{
436
putChar(
']'
);
437
mode = 0;
438
printChar(ch);
439
}
440
break
;
441
case
2:
// перед этим было введено ]~
442
switch
(ch) {
443
case
'4'
: setScreenMode(SCREEN_MODE_480); mode = 9;
444
break
;
445
case
'5'
: setScreenMode(SCREEN_MODE_512); mode = 9;
446
break
;
447
case
'6'
: setCharSize(CHAR_SIZE_6x8); mode = 9;
448
break
;
449
case
'8'
: setCharSize(CHAR_SIZE_8x8); mode = 9;
450
break
;
451
case
'C'
: memset(buf, 0, SCR_BUFFER_WIDTH*NUM_SCAN_LINES); setXYchar(0, 0); mode = 9;
452
break
;
453
case
'L'
: newX = 0; mode = 3;
454
break
;
455
case
'M'
: newX = 0; mode = 5;
456
break
;
457
case
'P'
: newX = 0; mode = 7;
458
break
;
459
460
case
'U'
: setCodePage(CP_UTF8); mode = 9;
461
break
;
462
case
'1'
: setCodePage(CP_1251); mode = 9;
463
break
;
464
case
'A'
: setCodePage(CP_866); mode = 9;
465
break
;
466
case
'K'
: setCodePage(CP_KOI8); mode = 9;
467
break
;
468
469
default
:
470
putChar(
']'
);
471
putChar(
'~'
);
472
mode = 0;
473
}
474
break
;
475
case
3:
// линия, ввод X (введено ]~L)
476
if
((ch >=
'0'
) && (ch <=
'9'
)) newX = newX*10 + (ch -
'0'
);
477
else
478
if
(ch ==
'x'
) {
479
newY = 0;
480
mode = 4;
481
}
else
mode = 0;
482
break
;
483
case
4:
// линия, ввод Y (введено ]~LXXXx)
484
if
((ch >=
'0'
) && (ch <=
'9'
)) newY = newY*10 + (ch -
'0'
);
485
else
486
if
(ch ==
'$'
) {
487
if
(newX >= lenLine*8) newX = lenLine*8-1;
488
if
(newY >= NUM_SCAN_LINES) newY = NUM_SCAN_LINES-1;
489
lineTo(newX, newY);
490
mode = 9;
491
}
else
mode = 0;
492
break
;
493
case
5:
// перемещение, ввод X (введено ]~M)
494
if
((ch >=
'0'
) && (ch <=
'9'
)) newX = newX*10 + (ch -
'0'
);
495
else
496
if
(ch ==
'x'
) {
497
newY = 0;
498
mode = 6;
499
}
else
mode = 0;
500
break
;
501
case
6:
// перемещение позиции рисования, ввод Y (введено ]~MXXXx)
502
if
((ch >=
'0'
) && (ch <=
'9'
)) newY = newY*10 + (ch -
'0'
);
503
else
504
if
(ch ==
'$'
) {
505
if
(newX >= lenLine*8) newX = lenLine*8-1;
506
if
(newY >= NUM_SCAN_LINES) newY = NUM_SCAN_LINES-1;
507
setXYpix(newX, newY);
508
mode = 9;
509
}
else
mode = 0;
510
break
;
511
case
7:
// перемещение позиции вывода текста, ввод X (введено ]~P)
512
if
((ch >=
'0'
) && (ch <=
'9'
)) newX = newX*10 + (ch -
'0'
);
513
else
514
if
(ch ==
'x'
) {
515
newY = 0;
516
mode = 8;
517
}
else
mode = 0;
518
break
;
519
case
8:
// перемещение, ввод Y (введено ]~PXXXx)
520
if
((ch >=
'0'
) && (ch <=
'9'
)) newY = newY*10 + (ch -
'0'
);
521
else
522
if
(ch ==
'$'
) {
523
if
(newX >= (lenLine*8 - charWidth)) newX = lenLine*8 - charWidth - 1;
524
if
(newY >= (NUM_SCAN_LINES-8)) newY = NUM_SCAN_LINES-9;
525
setXYchar(newX, newY);
526
mode = 9;
527
}
else
mode = 0;
528
break
;
529
}
530
}
файлы фонтов:
a_Small_Rus.c
001
#if defined(__AVR__)
002
#include <avr/pgmspace.h>
003
#define fontdatatype const uint8_t
004
#elif defined(__PIC32MX__)
005
#define PROGMEM
006
#define fontdatatype const unsigned char
007
#elif defined(__arm__)
008
#define PROGMEM
009
#define fontdatatype const unsigned char
010
#endif
011
012
// New font 177 symbols 5x8 = 885+4 bytes
013
014
fontdatatype SmallFont6[] PROGMEM =
015
{
016
0x05, 0x08, 0x20, 0xb1,
017
0x00, 0x00, 0x00, 0x00, 0x00,
// 32 sp
018
0x00, 0x00, 0x2f, 0x00, 0x00,
// 33 !
019
0x00, 0x07, 0x00, 0x07, 0x00,
// 34 "
020
0x14, 0x7f, 0x14, 0x7f, 0x14,
// 35 #
021
0x24, 0x2a, 0x7f, 0x2a, 0x12,
// 36 $
022
0x23, 0x13, 0x08, 0x64, 0x62,
// 37 %
023
0x36, 0x49, 0x55, 0x22, 0x50,
// 38 &
024
0x00, 0x05, 0x03, 0x00, 0x00,
// 39 '
025
0x00, 0x1c, 0x22, 0x41, 0x00,
// 40 (
026
0x00, 0x41, 0x22, 0x1c, 0x00,
// 41 )
027
0x14, 0x08, 0x3E, 0x08, 0x14,
// 42 *
028
0x08, 0x08, 0x3E, 0x08, 0x08,
// 43 +
029
0x00, 0x00, 0xA0, 0x60, 0x00,
// 44 ,
030
0x08, 0x08, 0x08, 0x08, 0x08,
// 45 -
031
0x00, 0x60, 0x60, 0x00, 0x00,
// 46 .
032
0x20, 0x10, 0x08, 0x04, 0x02,
// 47 /
033
034
0x3E, 0x51, 0x49, 0x45, 0x3E,
// 48 0
035
0x00, 0x42, 0x7F, 0x40, 0x00,
// 49 1
036
0x42, 0x61, 0x51, 0x49, 0x46,
// 50 2
037
0x21, 0x41, 0x45, 0x4B, 0x31,
// 51 3
038
0x18, 0x14, 0x12, 0x7F, 0x10,
// 52 4
039
0x27, 0x45, 0x45, 0x45, 0x39,
// 53 5
040
0x3C, 0x4A, 0x49, 0x49, 0x30,
// 54 6
041
0x01, 0x71, 0x09, 0x05, 0x03,
// 55 7
042
0x36, 0x49, 0x49, 0x49, 0x36,
// 56 8
043
0x06, 0x49, 0x49, 0x29, 0x1E,
// 57 9
044
0x00, 0x36, 0x36, 0x00, 0x00,
// 58 :
045
0x00, 0x56, 0x36, 0x00, 0x00,
// 59 ;
046
0x08, 0x14, 0x22, 0x41, 0x00,
// 60 <
047
0x14, 0x14, 0x14, 0x14, 0x14,
// 61 =
048
0x00, 0x41, 0x22, 0x14, 0x08,
// 62 >
049
0x02, 0x01, 0x51, 0x09, 0x06,
// 63 ?
050
051
0x32, 0x49, 0x59, 0x51, 0x3E,
// 64 @
052
0x7C, 0x12, 0x11, 0x12, 0x7C,
// 65 A
053
0x7F, 0x49, 0x49, 0x49, 0x36,
// 66 B
054
0x3E, 0x41, 0x41, 0x41, 0x22,
// 67 C
055
0x7F, 0x41, 0x41, 0x22, 0x1C,
// 68 D
056
0x7F, 0x49, 0x49, 0x49, 0x41,
// 69 E
057
0x7F, 0x09, 0x09, 0x09, 0x01,
// 70 F
058
0x3E, 0x41, 0x49, 0x49, 0x7A,
// 71 G
059
0x7F, 0x08, 0x08, 0x08, 0x7F,
// 72 H
060
0x00, 0x41, 0x7F, 0x41, 0x00,
// 73 I
061
0x20, 0x40, 0x41, 0x3F, 0x01,
// 74 J
062
0x7F, 0x08, 0x14, 0x22, 0x41,
// 75 K
063
0x7F, 0x40, 0x40, 0x40, 0x40,
// 76 L
064
0x7F, 0x02, 0x0C, 0x02, 0x7F,
// 77 M
065
0x7F, 0x04, 0x08, 0x10, 0x7F,
// 78 N
066
0x3E, 0x41, 0x41, 0x41, 0x3E,
// 79 O
067
068
0x7F, 0x09, 0x09, 0x09, 0x06,
// 80 P
069
0x3E, 0x41, 0x51, 0x21, 0x5E,
// 81 Q
070
0x7F, 0x09, 0x19, 0x29, 0x46,
// 82 R
071
0x46, 0x49, 0x49, 0x49, 0x31,
// 83 S
072
0x01, 0x01, 0x7F, 0x01, 0x01,
// 84 T
073
0x3F, 0x40, 0x40, 0x40, 0x3F,
// 85 U
074
0x1F, 0x20, 0x40, 0x20, 0x1F,
// 86 V
075
0x3F, 0x40, 0x38, 0x40, 0x3F,
// 87 W
076
0x63, 0x14, 0x08, 0x14, 0x63,
// 88 X
077
0x07, 0x08, 0x70, 0x08, 0x07,
// 89 Y
078
0x61, 0x51, 0x49, 0x45, 0x43,
// 90 Z
079
0x00, 0x7F, 0x41, 0x41, 0x00,
// 91 [
080
0x01, 0x06, 0x08, 0x30, 0x40,
// 92 Backslash
081
0x00, 0x41, 0x41, 0x7F, 0x00,
// 93 ]
082
0x04, 0x02, 0x01, 0x02, 0x04,
// 94 ^
083
0x40, 0x40, 0x40, 0x40, 0x40,
// 95 _
084
085
0x00, 0x03, 0x05, 0x00, 0x00,
// 96 `
086
0x20, 0x54, 0x54, 0x54, 0x78,
// 97 a
087
0x7F, 0x48, 0x44, 0x44, 0x38,
// 98 b
088
0x38, 0x44, 0x44, 0x44, 0x20,
// 99 c
089
0x38, 0x44, 0x44, 0x48, 0x7F,
// 100 d
090
0x38, 0x54, 0x54, 0x54, 0x18,
// 101 e
091
0x08, 0x7E, 0x09, 0x01, 0x02,
// 102 f
092
0x18, 0xA4, 0xA4, 0xA4, 0x7C,
// 103 g
093
0x7F, 0x08, 0x04, 0x04, 0x78,
// 104 h
094
0x00, 0x44, 0x7D, 0x40, 0x00,
// 105 i
095
0x40, 0x80, 0x84, 0x7D, 0x00,
// 106 j
096
0x7F, 0x10, 0x28, 0x44, 0x00,
// 107 k
097
0x00, 0x41, 0x7F, 0x40, 0x00,
// 108 l
098
0x7C, 0x04, 0x18, 0x04, 0x78,
// 109 m
099
0x7C, 0x08, 0x04, 0x04, 0x78,
// 110 n
100
0x38, 0x44, 0x44, 0x44, 0x38,
// 111 o
101
102
0xFC, 0x24, 0x24, 0x24, 0x18,
// 112 p
103
0x18, 0x24, 0x24, 0x18, 0xFC,
// 113 q
104
0x7C, 0x08, 0x04, 0x04, 0x08,
// 114 r
105
0x48, 0x54, 0x54, 0x54, 0x20,
// 115 s
106
0x04, 0x3F, 0x44, 0x40, 0x20,
// 116 t
107
0x3C, 0x40, 0x40, 0x20, 0x7C,
// 117 u
108
0x1C, 0x20, 0x40, 0x20, 0x1C,
// 118 v
109
0x3C, 0x40, 0x30, 0x40, 0x3C,
// 119 w
110
0x44, 0x28, 0x10, 0x28, 0x44,
// 120 x
111
0x1C, 0xA0, 0xA0, 0xA0, 0x7C,
// 121 y
112
0x44, 0x64, 0x54, 0x4C, 0x44,
// 122 z
113
0x00, 0x10, 0x7C, 0x82, 0x00,
// 123 {
114
0x00, 0x00, 0xFF, 0x00, 0x00,
// 124 |
115
0x00, 0x82, 0x7C, 0x10, 0x00,
// 125 }
116
0x08, 0x04, 0x08, 0x10, 0x08,
// 126 ~
117
//0x7C, 0x12, 0x11, 0x12, 0x7C, // 127 А ->33
118
119
0x7F, 0x49, 0x49, 0x49, 0x31,
// 128 Б 95
120
//0x7F, 0x45, 0x45, 0x45, 0x3A, // 129 В ->34
121
0x7F, 0x01, 0x01, 0x01, 0x03,
// 130 Г 96
122
0x60, 0x3F, 0x21, 0x3F, 0x60,
// 131 Д 97
123
//0x7F, 0x49, 0x49, 0x49, 0x41, // 132 Е ->37
124
0x73, 0x0C, 0x7F, 0x0C, 0x73,
// 133 Ж 98
125
0x21, 0x41, 0x49, 0x4D, 0x33,
// 134 З 99
126
0x7F, 0x10, 0x08, 0x04, 0x7F,
// 135 И 100
127
0x7E, 0x20, 0x11, 0x08, 0x7E,
// 136 Й 101
128
//0x7F, 0x08, 0x14, 0x22, 0x41, // 137 К ->43
129
0x40, 0x3F, 0x01, 0x01, 0x7F,
// 138 Л 102
130
//0x7F, 0x06, 0x08, 0x06, 0x7F, // 139 М ->45
131
//0x7F, 0x08, 0x08, 0x08, 0x7F, // 140 Н ->40
132
//0x3E, 0x41, 0x41, 0x41, 0x3E, // 141 О ->47
133
0x7F, 0x01, 0x01, 0x01, 0x7F,
// 142 П 103
134
//0x7F, 0x09, 0x09, 0x09, 0x06, // 143 Р ->48
135
136
//0x3E, 0x41, 0x41, 0x41, 0x22, // 144 С ->35
137
//0x03, 0x01, 0x7F, 0x01, 0x03, // 145 Т ->52
138
0x61, 0x26, 0x18, 0x06, 0x01,
// 146 У 104
139
0x1C, 0x22, 0x7F, 0x22, 0x1C,
// 147 Ф 105
140
//0x63, 0x14, 0x08, 0x14, 0x63, // 148 Х ->56
141
0x3F, 0x20, 0x20, 0x3F, 0x60,
// 149 Ц 106
142
0x07, 0x08, 0x08, 0x08, 0x7F,
// 150 Ч 107
143
0x7F, 0x40, 0x7F, 0x40, 0x7F,
// 151 Ш 108
144
0x3F, 0x20, 0x3F, 0x20, 0x7F,
// 152 Щ 109
145
0x01, 0x7F, 0x48, 0x48, 0x30,
// 153 Ъ 110
146
0x7F, 0x48, 0x78, 0x00, 0x7F,
// 154 Ы 111
147
0x7F, 0x48, 0x48, 0x30, 0x00,
// 155 Ь 112
148
0x41, 0x49, 0x49, 0x2A, 0x1C,
// 156 Э 113
149
0x7F, 0x10, 0x3E, 0x41, 0x3E,
// 157 Ю 114
150
0x66, 0x19, 0x09, 0x09, 0x7F,
// 158 Я 115
151
//0x20, 0x54, 0x54, 0x78, 0x40, // 159 а ->65
152
153
0x3E, 0x49, 0x45, 0x45, 0x38,
// 160 б 116
154
0x7E, 0x4A, 0x4A, 0x34, 0x00,
// 161 в 117
155
0x7C, 0x04, 0x04, 0x0C, 0x00,
// 162 г 118
156
0x38, 0x45, 0x45, 0x49, 0x3E,
// 163 д 119
157
//0x38, 0x54, 0x54, 0x54, 0x18, // 164 е ->69
158
0x4C, 0x30, 0x7C, 0x30, 0x4C,
// 165 ж 120
159
0x24, 0x42, 0x4A, 0x34, 0x00,
// 166 з 121
160
0x7C, 0x20, 0x10, 0x7C, 0x00,
// 167 и 122
161
0x7C, 0x21, 0x11, 0x7C, 0x00,
// 168 й 123
162
0x7C, 0x10, 0x28, 0x44, 0x00,
// 169 к 124
163
0x40, 0x3C, 0x04, 0x04, 0x7C,
// 170 л 125
164
0x7C, 0x08, 0x10, 0x08, 0x7C,
// 171 м 126
165
0x7C, 0x10, 0x10, 0x7C, 0x00,
// 172 н 127
166
//0x38, 0x44, 0x44, 0x44, 0x38, // 173 о ->79
167
0x7C, 0x04, 0x04, 0x7C, 0x00,
// 174 п 128
168
//0xFC, 0x18, 0x24, 0x24, 0x18, // 175 р ->80
169
170
//0x38, 0x44, 0x44, 0x44, 0x28, // 176 с ->67
171
0x04, 0x04, 0x7C, 0x04, 0x04,
// 177 т 129
172
//0x4C, 0x90, 0x90, 0x90, 0x7C, // 178 у ->89
173
0x18, 0x24, 0x7E, 0x24, 0x18,
// 179 ф 130
174
//0x44, 0x28, 0x10, 0x28, 0x44, // 180 х ->88
175
0x3C, 0x20, 0x20, 0x3C, 0x60,
// 181 ц 131
176
0x1C, 0x10, 0x10, 0x7C, 0x00,
// 182 ч 132
177
0x7C, 0x40, 0x7C, 0x40, 0x7C,
// 183 ш 133
178
0x3C, 0x20, 0x3C, 0x20, 0x7C,
// 184 щ 134
179
0x04, 0x7C, 0x50, 0x70, 0x00,
// 185 ъ 135
180
0x7C, 0x50, 0x70, 0x00, 0x7C,
// 186 ы 136
181
0x7C, 0x50, 0x70, 0x00, 0x00,
// 187 ь 137
182
0x42, 0x42, 0x52, 0x52, 0x3C,
// 188 э 138
183
0x7C, 0x10, 0x38, 0x44, 0x38,
// 189 ю 139
184
0x40, 0x2C, 0x12, 0x7E, 0x00,
// 190 я 140
185
0x7E, 0x4B, 0x4A, 0x4B, 0x42,
// 191 Ё D0 81 141
186
187
0x38, 0x55, 0x54, 0x55, 0x18,
// 192 ё D1 91 142
188
0x7C, 0x04, 0x05, 0x04, 0x00,
// 193 81 129 Ѓ D0 83 143
189
0x00, 0x78, 0x0A, 0x09, 0x00,
// 194 83 131 ѓ D1 93 144
190
0x3E, 0x49, 0x49, 0x41, 0x22,
// 195 AA 170 Є D0 84 145
191
0x38, 0x54, 0x54, 0x44, 0x28,
// 196 BA 186 є D1 94 146
192
//0x00, 0x41, 0x7F, 0x41, 0x00, // 197 B2 178 І D0 86 ->41
193
//0x00, 0x44, 0x7D, 0x40, 0x00, // 198 B3 179 і D1 96 ->73
194
0x00, 0x45, 0x7C, 0x45, 0x00,
// 199 AF 175 Ї D0 87 147
195
0x00, 0x45, 0x7C, 0x41, 0x00,
// 200 BF 191 ї D1 97 148
196
0x23, 0x44, 0x39, 0x04, 0x03,
// 201 A1 161 Ў D0 8E 149
197
0x24, 0x49, 0x32, 0x09, 0x04,
// 202 A2 162 ў D1 9E 150
198
0x7E, 0x02, 0x02, 0x02, 0x01,
// 203 A5 165 Ґ D2 90 151
199
0x7C, 0x04, 0x04, 0x02, 0x00,
// 204 B4 180 ґ D2 91 152
200
0x00, 0x4A, 0x55, 0x29, 0x00,
// 205 A7 167 § C2 A7 153
201
0x00, 0x06, 0x09, 0x09, 0x06,
// 206 ° C2 B0 154
202
0x44, 0x44, 0x5F, 0x44, 0x44,
// 207 B1 177 ± C2 B1 155
203
204
0x7C, 0x10, 0x10, 0x3C, 0x40,
// 208 B5 181 µ C2 B5 156
205
};
и font_c.c:
001
#include <avr/pgmspace.h>
002
003
const
unsigned
char
font_c[] PROGMEM = {
// "жирный" фонт 8х8
004
0, 0, 0, 0, 0, 0, 0, 0,
// 32 0
005
24, 60, 60, 24, 24, 0, 24, 0,
// 33 ! 1
006
54, 54, 20, 0, 0, 0, 0, 0,
// 34 " 2
007
54, 54, 127, 54, 127, 54, 54, 0,
// 35 # 3
008
8, 60, 2, 28, 32, 30, 8, 0,
// 36 $ 4
009
6, 102, 48, 24, 12, 102, 96, 0,
// 37 % 5
010
30, 51, 30, 10, 83, 51, 126, 0,
// 38 & 6
011
24, 24, 24, 12, 0, 0, 0, 0,
// 39 ' 7
012
48, 24, 12, 12, 12, 24, 48, 0,
// 40 ( 8
013
12, 24, 48, 48, 48, 24, 12, 0,
// 41 ) 9
014
0, 54, 28, 127, 28, 54, 0, 0,
// 42 * 10
015
0, 8, 8, 62, 8, 8, 0, 0,
// 43 + 11
016
0, 0, 0, 24, 24, 24, 12, 0,
// 44 , 12
017
0, 0, 0, 60, 0, 0, 0, 0,
// 45 - 13
018
0, 0, 0, 0, 0, 24, 24, 0,
// 46 . 14
019
0, 96, 48, 24, 12, 6, 0, 0,
// 47 / 15
020
60, 102, 118, 110, 102, 102, 60, 0,
// 48 0 16
021
24, 24, 28, 24, 24, 24, 126, 0,
// 49 1 17
022
60, 102, 96, 48, 12, 6, 126, 0,
// 50 2 18
023
60, 102, 96, 56, 96, 102, 60, 0,
// 51 3 19
024
48, 56, 52, 50, 126, 48, 48, 0,
// 52 4 20
025
126, 6, 62, 96, 96, 102, 60, 0,
// 53 5 21
026
60, 102, 6, 62, 102, 102, 60, 0,
// 54 6 22
027
126, 102, 48, 48, 24, 24, 24, 0,
// 55 7 23
028
60, 102, 102, 60, 102, 102, 60, 0,
// 56 8 24
029
60, 102, 102, 124, 96, 102, 60, 0,
// 57 9 25
030
0, 24, 24, 0, 24, 24, 0, 0,
// 58 : 26
031
0, 24, 24, 0, 24, 24, 12, 0,
// 59 ; 27
032
48, 24, 12, 6, 12, 24, 48, 0,
// 60 < 28
033
0, 0, 60, 0, 60, 0, 0, 0,
// 61 = 29
034
6, 12, 24, 48, 24, 12, 6, 0,
// 62 > 30
035
60, 102, 96, 56, 24, 0, 24, 0,
// 63 ? 31
036
28, 34, 58, 26, 66, 60, 0, 0,
// 64 @ 32
037
60, 102, 102, 126, 102, 102, 102, 0,
// 65 A 33
038
62, 102, 102, 62, 102, 102, 62, 0,
// 66 B 34
039
60, 102, 6, 6, 6, 102, 60, 0,
// 67 C 35
040
62, 102, 102, 102, 102, 102, 62, 0,
// 68 D 36
041
126, 6, 6, 62, 6, 6, 126, 0,
// 69 E 37
042
126, 6, 6, 62, 6, 6, 6, 0,
// 70 F 38
043
60, 102, 6, 6, 118, 102, 60, 0,
// 71 G 39
044
102, 102, 102, 126, 102, 102, 102, 0,
// 72 H 40
045
60, 24, 24, 24, 24, 24, 60, 0,
// 73 I 41
046
120, 48, 48, 48, 54, 54, 28, 0,
// 74 J 42
047
102, 54, 30, 14, 30, 54, 102, 0,
// 75 K 43
048
6, 6, 6, 6, 6, 6, 126, 0,
// 76 L 44
049
99, 119, 127, 107, 99, 99, 99, 0,
// 77 M 45
050
99, 103, 111, 123, 115, 99, 99, 0,
// 78 N 46
051
60, 102, 102, 102, 102, 102, 60, 0,
// 79 O 47
052
62, 102, 102, 102, 62, 6, 6, 0,
// 80 P 48
053
60, 102, 102, 102, 118, 60, 96, 0,
// 81 Q 49
054
62, 102, 102, 62, 30, 54, 102, 0,
// 82 R 50
055
60, 102, 6, 60, 96, 102, 60, 0,
// 83 S 51
056
126, 90, 24, 24, 24, 24, 24, 0,
// 84 T 52
057
102, 102, 102, 102, 102, 102, 60, 0,
// 85 U 53 (124->60)
058
102, 102, 102, 102, 102, 60, 24, 0,
// 86 V 54
059
99, 99, 99, 107, 127, 119, 99, 0,
// 87 W 55
060
99, 99, 54, 28, 54, 99, 99, 0,
// 88 X 56
061
102, 102, 102, 60, 24, 24, 24, 0,
// 89 Y 57
062
126, 96, 48, 24, 12, 6, 126, 0,
// 90 Z 58
063
60, 12, 12, 12, 12, 12, 60, 0,
// 91 [ 59
064
0, 6, 12, 24, 48, 96, 0, 0,
// 92 60 BackSlash
065
60, 48, 48, 48, 48, 48, 60, 0,
// 93 ] 61
066
8, 20, 34, 65, 0, 0, 0, 0,
// 94 ^ 62
067
0, 0, 0, 0, 0, 0, 60, 0,
// 95 _ 63
068
12, 12, 24, 0, 0, 0, 0, 0,
// 96 ` 64
069
0, 0, 60, 96, 124, 102, 124, 0,
// 97 a 65
070
6, 6, 6, 62, 102, 102, 62, 0,
// 98 b 66
071
0, 0, 60, 102, 6, 102, 60, 0,
// 99 c 67
072
96, 96, 96, 124, 102, 102, 124, 0,
// 100 d 68
073
0, 0, 60, 102, 126, 6, 60, 0,
// 101 e 69
074
56, 108, 12, 62, 12, 12, 12, 0,
// 102 f 70
075
0, 0, 124, 102, 102, 124, 96, 60,
// 103 g 71
076
6, 6, 6, 62, 102, 102, 102, 0,
// 104 h 72
077
0, 24, 0, 24, 24, 24, 60, 0,
// 105 i 73 (0, 6, 0, 6, 6, 6, 79, 0,)
078
48, 0, 48, 48, 54, 54, 28, 0,
// 106 j 74
079
6, 6, 102, 54, 30, 54, 102, 0,
// 107 k 75
080
24, 24, 24, 24, 24, 24, 24, 0,
// 108 l 76
081
0, 0, 99, 119, 127, 107, 107, 0,
// 109 m 77
082
0, 0, 62, 126, 102, 102, 102, 0,
// 110 n 78
083
0, 0, 60, 102, 102, 102, 60, 0,
// 111 o 79
084
0, 0, 62, 102, 102, 62, 6, 6,
// 112 p 80
085
0, 0, 30, 27, 27, 30, 88, 120,
// 113 q 81
086
0, 0, 62, 102, 102, 6, 6, 0,
// 114 r 82
087
0, 0, 124, 6, 60, 96, 62, 0,
// 115 s 83
088
0, 24, 24, 126, 24, 24, 24, 0,
// 116 t 84
089
0, 0, 102, 102, 102, 102, 124, 0,
// 117 u 85
090
0, 0, 102, 102, 102, 60, 24, 0,
// 118 v 86
091
0, 0, 99, 107, 107, 107, 62, 0,
// 119 w 87
092
0, 0, 102, 60, 24, 60, 102, 0,
// 120 x 88
093
0, 0, 102, 102, 124, 96, 60, 0,
// 121 y 89
094
0, 0, 60, 48, 24, 12, 60, 0,
// 122 z 90
095
56, 12, 12, 6, 12, 12, 56, 0,
// 123 { 91
096
8, 8, 8, 8, 8, 8, 8, 0,
// 124 | 92
097
14, 24, 24, 48, 24, 24, 14, 0,
// 125 } 93
098
0, 0, 92, 54, 0, 0, 0, 0,
// 126 ~ 94
099
//0, 0, 0, 0, 0, 0, 0, 0, // 127 BackSpace
100
//60, 102, 102, 126, 102, 102, 102, 0, // 127 А
101
126, 6, 62, 102, 102, 102, 62, 0,
// 128 Б 95
102
//62, 102, 102, 62, 102, 102, 62, 0, // 129 В
103
126, 6, 6, 6, 6, 6, 6, 0,
// 130 Г 96
104
56, 52, 54, 54, 54, 54, 127, 99,
// 131 Д 97
105
//126, 6, 6, 62, 6, 6, 126, 0, // 132 Е
106
219, 219, 90, 188, 90, 219, 219, 0,
// 133 Ж 98
107
60, 102, 96, 56, 96, 102, 60, 0,
// 134 З 99
108
102, 102, 102, 102, 118, 110, 102, 0,
// 135 И 100
109
24, 0, 102, 102, 118, 110, 102, 0,
// 136 Й 101
110
//102, 54, 30, 14, 30, 54, 102, 0, // 137 К
111
112, 104, 108, 108, 108, 108, 110, 0,
// 138 Л 102
112
//99, 119, 127, 107, 99, 99, 99, 0, // 139 М
113
//102, 102, 102, 126, 102, 102, 102, 0, // 140 Н
114
//60, 102, 102, 102, 102, 102, 60, 0, // 141 О
115
126, 102, 102, 102, 102, 102, 102, 0,
// 142 П 103
116
//62, 102, 102, 102, 62, 6, 6, 0, // 143 Р
117
//60, 102, 6, 6, 6, 102, 60, 0, // 144 С
118
//126, 90, 24, 24, 24, 24, 24, 0, // 145 Т
119
102, 102, 102, 124, 96, 102, 60, 0,
// 146 У 104
120
126, 219, 219, 219, 126, 24, 24, 0,
// 147 Ф 105 (254-126)
121
//99, 99, 54, 28, 54, 99, 99, 0, // 148 Х
122
51, 51, 51, 51, 51, 51, 127, 96,
// 149 Ц 106
123
102, 102, 102, 126, 96, 96, 96, 0,
// 150 Ч 107
124
99, 99, 107, 107, 107, 107, 127, 0,
// 151 Ш 108
125
99, 99, 107, 107, 107, 107, 255, 192,
// 152 Щ 109
126
7, 7, 62, 102, 230, 102, 62, 0,
// 153 Ъ 110
127
195, 195, 207, 219, 219, 219, 207, 0,
// 154 Ы 111
128
6, 6, 62, 102, 102, 102, 62, 0,
// 155 Ь 112
129
60, 102, 96, 120, 96, 102, 60, 0,
// 156 Э 113
130
115, 219, 219, 223, 219, 219, 115, 0,
// 157 Ю 114
131
124, 102, 102, 102, 120, 108, 102, 0,
// 158 Я 115
132
//0, 0, 60, 96, 124, 102, 124, 0, // 159 а
133
64, 60, 6, 62, 102, 102, 60, 0,
// 160 б 116
134
12, 22, 22, 14, 62, 102, 60, 0,
// 161 в 117
135
0, 0, 126, 6, 6, 6, 6, 0,
// 162 г 118
136
0, 0, 60, 54, 54, 54, 127, 99,
// 163 д 119
137
//0, 0, 60, 102, 126, 6, 60, 0, // 164 е
138
0, 0, 219, 90, 60, 90, 219, 0,
// 165 ж 120
139
0, 0, 60, 102, 48, 102, 60, 0,
// 166 з 121
140
0, 0, 102, 102, 118, 110, 102, 0,
// 167 и 122
141
24, 0, 102, 102, 118, 110, 102, 0,
// 168 й 123
142
0, 0, 102, 54, 30, 54, 102, 0,
// 169 к 124
143
0, 0, 112, 104, 108, 108, 110, 0,
// 170 л 125
144
0, 0, 99, 119, 107, 99, 99, 0,
// 171 м 126 (247,235-119,107)
145
0, 0, 102, 102, 126, 102, 102, 0,
// 172 н 127
146
//0, 0, 60, 102, 102, 102, 60, 0, // 173 о
147
0, 0, 126, 102, 102, 102, 102, 0,
// 174 п 128
148
//0, 0, 62, 102, 102, 62, 6, 6, // 175 Р
149
//0, 0, 60, 102, 6, 102, 60, 0, // 176 с
150
0, 0, 126, 24, 24, 24, 24, 0,
// 177 т 129
151
//0, 0, 102, 102, 124, 96, 60, 0, // 178 у
152
0, 0, 60, 90, 90, 90, 60, 24,
// 179 ф 130
153
//0, 0, 102, 60, 24, 60, 102, 0, // 180 х
154
0, 0, 51, 51, 51, 51, 127, 96,
// 181 ц 131
155
0, 0, 102, 102, 126, 96, 96, 0,
// 182 ч 132
156
0, 0, 99, 107, 107, 107, 127, 0,
// 183 ш 133
157
0, 0, 99, 107, 107, 107, 255, 192,
// 184 щ 134
158
0, 0, 7, 62, 102, 102, 62, 0,
// 185 ъ 135
159
0, 0, 195, 207, 219, 219, 207, 0,
// 186 ы 136
160
0, 0, 6, 62, 102, 102, 62, 0,
// 187 ь 137
161
0, 0, 60, 98, 120, 98, 60, 0,
// 188 э 138
162
0, 0, 115, 219, 223, 219, 115, 0,
// 189 ю 139
163
0, 0, 124, 102, 126, 108, 102, 0,
// 190 я 140
164
102, 0, 126, 6, 62, 6, 126, 0,
// 191 Ё 141
165
36, 0, 60, 102, 126, 6, 60, 0,
// 192 ё 142
166
48, 0, 126, 6, 6, 6, 6, 0,
// 193 Ѓ 143
167
96, 24, 0, 126, 6, 6, 6, 0,
// 194 ѓ 144
168
60, 102, 6, 30, 6, 102, 60, 0,
// 195 Є 145
169
0, 0, 60, 70, 30, 70, 60, 0,
// 196 є 146
170
//60, 24, 24, 24, 24, 24, 60, 0, // 197 І
171
//0, 24, 0, 24, 24, 24, 60, 0, // 198 і
172
54, 0, 60, 24, 24, 24, 60, 0,
// 199 Ї 147
173
0, 54, 0, 24, 24, 24, 60, 0,
// 200 ї 148
174
90, 102, 102, 124, 96, 102, 60, 0,
// 201 Ў 149
175
36, 24, 102, 102, 124, 96, 60, 0,
// 202 ў 150
176
32, 62, 6, 6, 6, 6, 6, 0,
// 203 Ґ 151
177
0, 32, 62, 6, 6, 6, 6, 0,
// 204 ґ 152
178
24, 6, 24, 102, 24, 96, 24, 0,
// 205 § 153
179
0, 28, 54, 54, 28, 0, 0, 0,
// 206 ° 154
180
0, 24, 24, 126, 24, 0, 126, 0,
// 207 ± 155
181
0, 0, 102, 102, 126, 102, 198, 6,
// 208 µ 156
182
};
На всякий случай напомню, что данный контроллер должен отображать на экране то, что передается ему извне, т.е. другого контроллера. Для проверки была использованка Mega со следующим скетчем:
001
#define SCREEN_MODE_480 0 // режим дисплея разрешением 480х240
002
#define SCREEN_MODE_512 1 // режим дисплея разрешением 512х240
003
#define CHAR_SIZE_6x8 0 // режим узких символов 6х8
004
#define CHAR_SIZE_8x8 1 // режим широких символов 8х8
005
#define CP_UTF8 0 // режим кодировки UTF-8
006
#define CP_1251 1 // режим кодировки CP-1251
007
#define CP_866 2 // режим кодировки CP-866 (Альтернативная ГОСТ)
008
#define CP_KOI8 3 // режим кодировки KOI8R
009
010
HardwareSerial * S = &Serial3;
011
012
void
printStr(
const
char
* ch) {
013
while
(*ch) { S->print((
char
)*ch++); }
014
}
015
016
void
setXYchar(
int
x,
int
y) {
017
S->print(
"]~P"
);
018
S->print(x);
019
S->print(
'x'
);
020
S->print(y);
021
S->print(
'$'
);
022
}
023
024
void
setCodePage(
int
page) {
// выбор кодовой страницы
025
const
char
m[4] = {
'U'
,
'1'
,
'A'
,
'K'
};
026
S->print(
"]~"
);
027
S->print(m[page]);
028
}
029
030
void
printCharSet(
int
x,
int
y, unsigned
char
b,
const
char
* ch) {
031
setXYchar(x,y);
032
printStr(ch);
033
int
jj = b > 127 ? 4 : 8;
034
int
ii = b == 0 ? 0 : 128;
035
for
(
int
j = 0; j < jj; j++) {
036
setXYchar(x,y+(j+1)*8);
037
for
(
int
i = 0; i < 16; i++) {
038
if
(b > 127) S->write(b);
039
S->print((
char
)(ii + j*16 + i));
040
}
041
}
042
}
043
044
045
void
sendSeq() {
046
// S->println("test");
047
S->print(
"]~4"
);
// mode 480x240
048
S->print(
"]~C"
);
// clear screen
049
S->print(
"]~P200x100$]~8H e l l o !"
);
050
S->print(
"]~P160x140$]~6Serial Terminal Display Test"
);
051
S->print(
"]~M140x80$]~L340x80$]~L340x160$]~L140x160$]~L140x80$"
);
// draw frame
052
Serial
.println(
"OK!"
);
053
delay(4000);
054
055
S->print(
"]~C"
);
056
for
(
int
i = 0; i < 128; i++) {
057
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
058
}
059
delay(4000);
060
S->print(
"]~5"
);
061
delay(4000);
062
for
(
int
i = 0; i < 128; i++) {
063
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
064
}
065
delay(4000);
066
S->print(
"]~8"
);
067
for
(
int
i = 0; i < 128; i++) {
068
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
069
}
070
delay(4000);
071
S->print(
"]~4"
);
072
delay(4000);
073
for
(
int
i = 0; i < 128; i++) {
074
S->print(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz.."
);
075
}
076
delay(4000);
077
S->print(
"]~5"
);
078
delay(4000);
079
S->print(
"]~C"
);
080
for
(
int
i = 0; i < 1024; i++) {
081
S->print(
"]~L"
);
082
S->print(random(512));
083
S->print(
"x"
);
084
S->print(random(240));
085
S->print(
"$"
);
086
}
087
// delay(4000);
088
S->print(
"]~P228x108$ "
);
089
S->print(
"]~P228x116$ E N D "
);
090
S->print(
"]~P228x124$ "
);
091
delay(4000);
092
093
S->print(
"]~C"
);
094
S->print(
"]~8"
);
095
setCodePage(CP_UTF8);
096
S->print(
"]~P50x20$Work with different cyrillic codepages"
);
097
S->print(
"]~P50x30$Работа с различными кодировками кириллицы"
);
098
099
printCharSet(24, 54, 0,
"ASCII"
);
100
101
printCharSet(176, 54, 0xD0,
"UTF-8 D0"
);
102
printCharSet(328, 54, 0xD1,
"UTF-8 D1"
);
103
printCharSet(176, 104, 0xD2,
"UTF-8 D2"
);
104
printCharSet(328, 104, 0xC2,
"UTF-8 C2"
);
105
setCodePage(CP_1251);
106
printCharSet(176, 154, 2,
"CP-1251"
);
107
setCodePage(CP_866);
108
printCharSet(328, 154, 2,
"CP-866"
);
109
setCodePage(CP_KOI8);
110
printCharSet(24, 154, 2,
"CP-KOI8R"
);
111
delay(4000);
112
113
}
114
115
void
setup
() {
116
// put your setup code here, to run once:
117
// pinMode(2,OUTPUT);
118
// tone(2, 4000);
119
S->begin(9600);
120
Serial
.begin(115200);
121
sendSeq();
122
}
123
124
void
loop
() {
125
// put your main code here, to run repeatedly:
126
127
}
Для того, чтобы добиться желаемого результата вход контроллера stm32 Serial1 должен быть подключен к выходу Меги Serial3.
Вообще-то, смысл вашего проекта наверное в том, чтобы наложить надписи на видео от другого источника. Сразу приходят на ум: ОСД для дрона самопального, какой-то радар заднего хода автомобиля с выводом растояний и положения помехи на экран медиасистема, смешанный с видео от камеры заднего вида и т.п.
А вот как VGA не уверен, что кому-то будет интересно. Тем более что аналоговых телеков пока еще дофига, а вот монитор лишним не бывает, всегда куда-то нужнее, чем ардуино к нему подключать.
Только для реализации ОСД что-то нужна схематика микшера видео, и синхронизация от внешнего источника видео.
Вообще-то, я что-то похожее на ОСД на 328-ом видел, на форуме любителей радимоделей.
почему бы не использовать делитель на 5 (72/5=14.4, близко к 14.318), если используешь внешнюю синхронизацию, и тогда с строками длительностью в 63.5мкс, (NTSC timing)
можно будет как усеченный PAL-M или NTSC использовать.
отдельно буфер строки 904, 912 или 920 бит (113, 114 или 115 байт, 904 укладывается в стандарт, 912 чуть перебором, а 920 уже за пределами ntsc) и там как колорбурст так и цвет выводить.
пауза (0-ли), (после синхросигнала 5 байт 0xBB или 11001100), пауза (0-ли), потом цвет в виде декодированной последовательности (abcd)(efgh) - две тетрады.
чуть позже дополню с тетрадами, в ods посчитаю варианты как pal так и ntsc.
для пал подсчитал сочетания, если как у Вас 1 битное:
0000-0000
0001-0100
1001-1100
1110-1011
1011-1110
1111-1111
это стандрартные rgb, нечётный и четные строки, т.е. последовательно 16 цветов, но в 1битном кодировании PAL получилось только 6 независимых цветов.
по NTSC наверняка можно обыграть все 16 комбинаций 4битовых последовательностей, но какие они дадут цвета - не могу сказать, надо пробовать.
я попробую с использованием двух SPI каналов, двухбитные последовательности.
в виде двух буферов по 228 байт, и выдача параллельно с PA6 и PB9 через резисторы 580 и 240 Ом,
и 0 - на обоих бит=0, 1 на 1=1, на 2=0, 2 на 1=0, на 2=1, и 3 на 1=1, на 2=1.
и конденсатор там не нужен. выход нагружен входным сопротивлением в 75 ом.
тогда возможно будут такие комбинации:
всего 11 комбинаций.
отдельно буфер строки 904, 912 или 920 бит (113, 114 или 115 байт...
904*240/8=27120 байт, откуда в BluePill столько памяти?
Там на байт несколько точек. Вы же сами по spi выдаёте сигнал.
А тут сигнал на частоте цветоразностной сразу даёт цвет по pal или ntsc.
У меня указаны битовые последовательности в случае 1 спи (0/1)
Или при использовании 2 спи 0 (синхро), оба канала на 0, 1(с большим резистором в 1, 2 меньший резистор в1, больший в 0, 3 оба в единице.
Если использовать делитель 10, будет 4 точки на байт и на 1 спи.
И буфер не предлагаю сразу на весь экран, это буфер строки. Пока одна передается, другая формируется или от знакогенератора и текстового буфера, или с строки из графического фрейм буфера.
Другого простого варианта сделать унифицированный вывод видео при разных входных данных и двух немного разных методах кодирования цвета.
И буфер строки формируется на всю строку, на 64мксек. Тогда 20% неизменно, а 80% формируется из известных данных. Потом по таймеру запускаем спи и формируем четную строку, делаем другие задачи.
Тут можно любую ртос с переключением таймером в 15734/15625 раз. На таймере запуск спи и инициация заполнения 2 буфера.
Получаем при вашей схеме дополнительно 2*114 байт на 2 строки, если быстрый контроллер, то можно в онлайн формировать, 1 буфером.
Вам же и цвет и кучу всего захочется.
А тут сделать механизм формирования строки и не важно, какой буфер в целом и как им пользуются, лишь бы период формирования строки укладывался в 64 мксек.
Каков объем графического фрейм буфера 904х240 точек?
Чтобы "формировать" строку, надо откуда-то брать данные. Откуда брать данные для графического экрана? Вы знаете другой источник информации кроме фрейм буфера?
елы-палы. есть графический фрейм-буфер или текстовый фрейм-буфер, т.е. массив байт грубо говоря 80х24.
используем 2 буфера строк по 904..912 точек. ссылка на следующий буфер, номер строки, чет/нечет полукадр,
обычная задача по семафору, имея переменную номер строки, четный или нечетный полукадр, ссылку на строчный буфер и исходные данные - рисует как ей душа пожелает.
когда происходит вызов переполнения таймера строки (15625 или 15734 Гц) выбор:
ссылки на строковые буфера: новый=предыдущий, текущий=следующий, следующий=новый.
запускаем spi,
увеличиваем номер новой строки. если он больше>262+четный&1, то номер=1, четный=(++четный)&1.
(это я сразу пишу в с кодировании)
работа с новым буфером - если следующая с изображением - то семафор на формирование следующей строки изображения,
иначе какая там необходима строка - кадровый синхро-импульс, строковый, просто "чёрная" строка... можно взять заранее заготовленные.
в этих 904 строках 20% практически неизменны, это вне отображаемого пространства.
а около 704..720 точек - их сочетание по тетрадам, т.е. на 177..180 точек даст всевозможные состояния. выше - цветное разрешение сложно предсказать.
если будет ч/б изображение - после строкового импульса не выставлять color burst и будет чб сигнал высокого разрешения, до 704..720 точек разрешающей способности. и можно все поля сделать детально по стандарту.
тогда, если формирование буфера строки не прерываемо планировщиком - то в строках не будет помех, будет независимость от состояния исходного буфера.
если свести до графики CGA адаптера, т.е. 4 цвета 320х200, то можно использовать 1spi, и делитель на синхросигнал для spi будет равен 10, т.е. синхросихнал будет 7.2МГц, тогда строчный буфер можно в 2 раза уменьшить.
при использовании 1spi+1 вывод синхро, как у тебя, то при 3.3V, 2 резистора номиналом 560 ом на синхро, 220 ом на spi - получим при 75ом входной нагрузки 0, 0.3, 1.06 вольт. т.е. монохромный или в случае color burst цветной сигнал одной тональности.
я на выходных поищу bluepill и накарябаю код. заведу через rca или scart на дисплей, посмотрю что получится.
можно для расширения диапазона использовать 2spi и оба синхронизировать с делителя, тогда у нас получится 4 значения напряжений:
0, 0.3, 0.76, 1.06 вольт. - с ними вариантов будет больше.
"В огороде бузина, а в Киеве - дядька."
Я не спрашивал, как реализовать текстовый буфер.
И меня совершенно не интересует режим "как CGA" 320х200.
Тем более, я ничего не спрашивал про резисторы.
Меня интересует один вопрос: как разместить графический буфер 904х240 в памяти BluePill? Желательно в цветном варианте.
е-ма, не весь буфер, а только буфер строки!!!
Что "буфер строки"?
Зачем мне буфер строки?
Где хранить то, что нарисовано на экране?
Это вторичный буфер, который не используется для работы пользователем, он в количестве двух штук используется прерыванием для организации вывода видео, а формирование его уже идёт хоть от текстового буфера, хоть от графического, хоть налету, например при распознавании postscript языка. Чтобы мог организовать хоть как в спектруме графические атрибуты, хоть на каждую точку rgba, текст. Вывод будет отвязанный от реализации основного буфера, связь через 1 функцию конверсии с основного буфера в строковый. Сначала отработать что мы можем вообще выжать из твоего варианта выдачи видеосигнала, а потом уже на основном буфере уже определиться как кодировать для пользователя.
Ну опять, я про Фому, а Вы - про Ерему!
zelya, у меня к Вам просьба: либо ответьте на вопрос из 3-й строки сообщения №26, либо заведите тему и пишите туда все, что хотите. Но не нужно помещать в данную тему то, что к ней не имеет ни малейшего отношения.
у меня несколько вопросов, в начале красава, достойное решение.
1. к монитору прикрутили?
2.115200 это макс скорость порта?
3. можно ли прикрутить клаву и ответ по uart в обратку сканов клавы
1. К какому монитору?
2. Строго говоря, там чистый USB, поэтому на физическую скорость эта константа влияния не оказывает.
3. Если есть синяя изолента - почему нет!
А почему не на esp? Ща врде блюпилы как крыло самолета стоят, да и памяти побольше в есп.
прикрутил 230400, полет нормальный, все устраивает.
прикладываю результат
https://youtu.be/_e-hXnwsUxU
убрать бы мусор и немного стабильности, и буду пытаться запилить свой маленький не доретро компик
А почему не на esp? Ща врде блюпилы как крыло самолета стоят, да и памяти побольше в есп.
1. Когда я покупал, было 105-110р. Пока не закончились.
2. Я не встречал нормального дэйташита на esp. Зато где-то слышал, что его в природе не существует.
Я начал возиться с аппаратной реализацией (нужно добавить одну-две простейшие логические микрухи), но наткнулся на непонятки. Потом выяснил, что конкретный экземпляр stm выдает на одной из используемых ног ненормальное напряжение (больше вольта логического нуля). Но к тому моменту занялся другими проектами и возвращаться к этому уже не хотелось.
из всех таких устройств, отношение цена, производительность и разрешение, это лучшее, даже если прикрутить пару элементов логики, копейки
хотелось бы увидеть итог
может чем помогу
Мне одному заметно что это не 4К? И даже вроде не HD...
Мне одному заметно что это не 4К? И даже вроде не HD...
Вы сударь, часом не ошиблись ссайтом малинки, попали на сайт арду. :-)
Понял. Тут можна поговнячить.. :-)
Понял. Тут можна поговнячить.. :-)
шкодить добрым саморитянам, но для чего. если есть достойные предложения, - тогда можно поерничать.
А засрать мона все, даже себе на полу дома
выяснил, что конкретный экземпляр stm выдает на одной из используемых ног ненормальное напряжение (больше вольта логического нуля).
дай попробую угадать, уж не разделяется ли эта нога с SERIAL?
дай попробую угадать, уж не разделяется ли эта нога с SERIAL?
Да и какая связь с Сериал, колись
дай попробую угадать, уж не разделяется ли эта нога с SERIAL?
Да и какая связь с Сериал, колись
я в важгаде пост выкладывал, об использовании третьего таймера, с осциллограммами, реплика была про грань добра и зла )))
казалось бы какая связь... плата другая. пины другие, аддон другой...
казалось бы какая связь... плата другая. пины другие, аддон другой...
а только наружная обвязка может подтягивать уровень, это либо LED либо SERIAL других не знаю, может они и есть, нужен пин нужна схема, чудес не бывает...правда еще бывает вжаренная логика )))
PS я жеж говорил - попробую угадать...
Мне одному заметно что это не 4К? И даже вроде не HD...
Сэр что-нибудь слышал о такой науке как арифметика?
Для HD нужно 1920*1080/8=259200 байт видеопамяти, где столько взять в Блупилле?
я в важгаде пост выкладывал, об использовании третьего таймера, с осциллограммами, реплика была про грань добра и зла )))
а, если подвесить вч транзистор (чтоб небыло мусора и задержки при использовании логики, тот же старый и добрый 315 или 361, в литературе их ставят в генераторы с логикой, чтоб поднять уровень и снизить завалы) в импульсном режиме, и пару элементов, чтоб поднять уровень и сделать реку меандру. помнится в старых компах и в импульсных устройствах выравнивали (делали прямые углы) завалы, сдвиг на пару нс я думаю не сильно скажется
Мне одному заметно что это не 4К? И даже вроде не HD...
Сэр что-нибудь слышал о такой науке как арифметика?
Да сэр! Арихетика - моя слабость. Все больше интригалы, да интригалы.
Мне одному заметно что это не 4К? И даже вроде не HD...
Для HD нужно 1920*1080/8=259200 байт видеопамяти, где столько взять в Блупилле?
А вот проблемы индейцев шерифа не волнуют. Выбираем правильно кристалл под задачу.
с интрегалами разобрались?. Займемся нашими патифонами, у кого есть предложения?
реализовать триггер шмидта https://uk-parkovaya.ru/wp-content/uploads/1/1/6/11635e811bf116fadc250ba...
руководствуясь к примеру https://lib.qrz.ru/node/5480
или типо того https://forum.cxem.net/uploads/monthly_12_2014/post-186391-0-76944100-14...
просто у меня нет осциллографа для измерения форм сигналов с частотой более 20 Мгц, а то бы помог. не разжился я ещё
может за основу, для формирования _П_П_П_ взять входной каскад на полевике из схемы https://fornk.ru/2990-samodelnyj-chastotomer-na-attiny2313/
А в чем вопрос-то?
LM393 и голову не морочить