Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.90/198: Рейтинг темы: голосов - 198, средняя оценка - 4.90
21 / 19 / 6
Регистрация: 25.11.2017
Сообщений: 708

Что за тип данных uint32_t?

30.07.2019, 22:34. Показов 40519. Ответов 171
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Это без знаковый int, который занимает 32 бита. А вот t, что значит?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
30.07.2019, 22:34
Ответы с готовыми решениями:

Как побитово скопировать uint32_t в float, минуя при этом выделения uint32_t в оперативную память
Всем привет, недавно заинтересовал такой вопрос ниже. Как ПОБИТОВО скопировать uint32_t в float, минуя при этом выделения uint32_t в...

Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?
Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?

Скажите пожалуйста, что это за тип данных?!
int **allocate2D(int rows, int cols) { int **arr2D; int i, j; arr2D = (int**)malloc(rows*sizeof(int*)); for(i=0;...

171
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.08.2019, 12:21
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Обратите внимание, что там нет никаких шаблонов и прочего трудноанализируемого синтаксиса.
Необходимость часть аргументов функции указать не в (круглых скобках), а <в угловых> это уже слишком сложно? Вот define которые могут раскрыться и в число, и в список аргументов, и просто внезапно сломать абсолютно невинный int min=1 это действительно сложно.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Приведите, пожалуйста, полный код. Те куски, что вы выкладывали раньше, собрать не получается.:
Это не в кусках проблема, а в компиляторе. Он у вас, судя по логам компиляции, if constexpr не понимает (gcc 8.3.0 понимает). Ну, еще чуточку усложним:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<cstdint>
#include<cstddef>
//пакет заглушек
std::uint8_t PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
                  PORTI, PORTJ, PORTK, PORTL, PORTM, PORTN, PORTO, PORTP,
                  PORTQ, PORTR, PORTS, PORTT, PORTU, PORTV, PORTW, PORTX,
                  PORTY, PORTZ;
 
class bitset{
public:
    static constexpr auto size = 32;
 
    constexpr bitset(){}
    constexpr bitset(unsigned shift,unsigned port){ data[port] = (1<<shift);}
    constexpr bitset operator | (const bitset&value) const {
        bitset res;
        for(unsigned pos=0; pos<size; ++pos)
            res.data[pos] = data[pos] | value.data[pos];
        return res;
    }
    constexpr uint8_t getByte(size_t pos) const { return data[pos]; }
private:
    uint8_t data[size] = {0};
};
 
constexpr bitset operator "" _pin(const char*str, size_t){
    return bitset (str[1]-'0',str[0]-'A');
}
 
constexpr bitset segmentA="A3"_pin;
constexpr bitset segmentB="D1"_pin;
constexpr bitset usedBits=segmentA|segmentB;
 
template<unsigned port>
uint8_t getMask(unsigned number){
    static const uint8_t data[10]={
        (segmentA|segmentB).getByte(port),
        segmentA.getByte(port),
        segmentB.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port)
    };
    return data[number];
}
 
template<unsigned portNumber,typename PortType>
void showNumber(unsigned number,PortType&port)
{
    if(usedBits.getByte(portNumber))
        port=(port&~usedBits.getByte(portNumber))|getMask<portNumber>(number);
}
 
template<unsigned portNumber,typename PortType,typename...Args>
void showNumber(unsigned number,PortType&port,Args&...args){
    if(usedBits.getByte(portNumber))
        port=(port&~usedBits.getByte(portNumber))|getMask<portNumber>(number);
    showNumber<portNumber+1,Args...>(number,args...);
}
 
void showNumber(unsigned number){
    showNumber<0>(number,
                  PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
                  PORTI, PORTJ, PORTK, PORTL, PORTM, PORTN, PORTO, PORTP,
                  PORTQ, PORTR, PORTS, PORTT, PORTU, PORTV, PORTW, PORTX,
                  PORTY, PORTZ
                 );
}
 
int main(){
  showNumber(0);
}
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
23.08.2019, 14:27
Цитата Сообщение от Renji Посмотреть сообщение
Необходимость часть аргументов функции указать не в (круглых скобках), а <в угловых> это уже слишком сложно? Вот define которые могут раскрыться и в число, и в список аргументов, и просто внезапно сломать абсолютно невинный int min=1 это действительно сложно.
Необходимость учить новый язык с новым синтаксисом и вообще подходом - сложно.
И макросы - сложно... было бы, если бы не использовались повсеместно. Впрочем, макросы проще в том, что это совершенно отдельный язык, никак не привязанный к Си. Достаточно понять, что макрос занимается подстановкой текста в исходный код перед началом компиляции. Так что define не может раскрыться ни в список аргументов, ни в число - только в строку.
Цитата Сообщение от Renji Посмотреть сообщение
Это не в кусках проблема, а в компиляторе.
Версия самая свежая
Code
1
2
$ avr-g++ -v
gcc version 5.4.0 (GCC)
Цитата Сообщение от Renji Посмотреть сообщение
Ну, еще чуточку усложним:
Code
1
main.c:4:18: fatal error: cstdint: Нет такого файла или каталога
Исправляю <cstdint> на <stdint.h> и <cstddef> на <stddef.h> до кучи.
Code
1
2
3
4
5
6
main.c:7:6: error: ‘uint8_t’ in namespace ‘std’ does not name a type
 std::uint8_t PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
      ^
main.c: In function ‘void showNumber(unsigned int)’:
main.c:70:19: error: ‘PORTA’ was not declared in this scope
                   PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
Исправляю std::uint8_t на обычный uint8_t:
Code
1
2
3
4
5
6
7
8
9
10
In file included from /usr/lib/avr/include/avr/io.h:99:0,
                 from main.c:1:
main.c:7:16: error: expected unqualified-id before ‘volatile’
 uint8_t PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
                ^
main.c:7:16: error: expected ‘)’ before ‘volatile’
main.c:7:16: error: expected ‘)’ before ‘volatile’
main.c: In function ‘void showNumber(unsigned int)’:
main.c:70:47: error: ‘PORTE’ was not declared in this scope
#то же самое для остальных портов
Ладно, фиг с ними, с портами. Пока что вручную убираю PORTB - PORTD чтобы скомпилировалось:
Code
1
2
3
4
5
6
7
8
9
10
11
$ avr-g++ -std=c++17 main.c -mmcu=atmega8 -Os -DF_CPU=1000000 -o a.elf -Wall -Wextra -Wpedantic
$ avr-size -C a.elf 
AVR Memory Usage
----------------
Device: Unknown
 
Program:     170 bytes
(.text + .data + .bootloader)
 
Data:         43 bytes
(.data + .bss + .noinit)
Для сравнения, размер моего варианта:
Code
1
2
3
4
5
6
7
8
9
10
11
$ avr-g++ main.c -mmcu=atmega8 -Os -DF_CPU=1000000 -o a.elf
$ avr-size -C a.elf 
AVR Memory Usage
----------------
Device: Unknown
 
Program:     146 bytes
(.text + .data + .bootloader)
 
Data:          0 bytes
(.data + .bss + .noinit)
Если не проводить инициализацию (настройку портов на выход) то размер снижается до 128 байт.
Впрочем, эту разницу я готов списать на косяки реализации avr-g++.
Ах да! Вы же не указали компилятору хранить массивы во флеш-памяти! Ну и для максимально тепличных условий даже удалю лишние порты:
C++
1
2
3
4
5
PROGMEM static const uint8_t data[10]={
...
return pgm_read_byte(&data[number]);
...
showNumber<0>(number, PORTB, PORTC, PORTD);
Code
1
2
3
4
5
6
7
8
9
10
$ avr-size -C a.elf 
AVR Memory Usage
----------------
Device: Unknown
 
Program:     130 bytes
(.text + .data + .bootloader)
 
Data:          0 bytes
(.data + .bss + .noinit)
Откуда берется два лишних байта флеша я пока не понял, но это уже точно статистическая погрешность.
Если вы не собираетесь своим кодом пользоваться дальше (я-то не собираюсь точно: мой вариант нагляднее), предлагаю на этом остановиться: вам удалось выжать из С++ эффективность и универсальность не хуже, чем на Си.
Тем более, что пока мы мерились изяществом кода, отошли от главного: насколько такой код будет читаемым и сопровождаемым для рандомного программиста? Предлагаю эксперимент: я немного допиливаю ваш код, чтобы он нормально собирался (я так понял, у вас компилятора под AVR нет, так что мне это проще), после чего создаем в разделе AVR соответствующую тему с просьбой оценить оба варианта: какой покажется народу более простым и каким бы они предпочли пользоваться.
Кроме этого могу подобрать еще какую-нибудь практическую задачу, на которой можно поупражнять знания макросов и шаблонов, если вам это интересно, конечно.
Я все еще рассматриваю наш спор как средство узнать что-то новое как для вас, так и для себя.
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
23.08.2019, 14:43
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Версия самая свежая
5.4.0 это не 8.3.0

Добавлено через 2 минуты
И он вышел в июне 2016 - https://gcc.gnu.org/releases.html . Какая там может быть поддержка С++17 ?

Добавлено через 2 минуты
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
у вас компилятора под AVR нет
gcc поддержку компиляции под Atmel AVR не прекращал.
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
23.08.2019, 15:09
Цитата Сообщение от TRam_ Посмотреть сообщение
5.4.0 это не 8.3.0
Откуда скачать более свежую версию именно под AVR? В репозитории Debian самая свежая эта.
Цитата Сообщение от TRam_ Посмотреть сообщение
gcc поддержку компиляции под Atmel AVR не прекращал.
Как и любой кросс-компилятор, avr-gcc надо устанавливать отдельно. У Renji, похоже, нет желания это делать.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.08.2019, 16:23
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Необходимость учить новый язык с новым синтаксисом и вообще подходом - сложно.
В задаче "решить на новом языке" изучение нового языка идет по умолчанию.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
gcc version 5.4.0 (GCC)
Трехлетней давности. Поставил, avr-компилятор, покрутил. Посмотрел ассемблерный листинг, сказал "что за фигня?" и ручками прописал inline. Код сократился раза в два. Посмотрел ассемблерный листинг еще раз, еще раз сказал "что за фигня?" и ручками прописал static на заглушки. Расходы памяти сократились в десять раз. Итого:
Program: 94 bytes
(.text + .data + .bootloader)

Data: 1 bytes
(.data + .bss + .noinit)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <inttypes.h>
#include <avr/pgmspace.h>
#include<stddef.h>
 
#ifndef PORTA
static uint8_t PORTA;
#endif
#ifndef PORTB
static uint8_t PORTB;
#endif
#ifndef PORTC
static uint8_t PORTC;
#endif
#ifndef PORTD
static uint8_t PORTD;
#endif
#ifndef PORTE
static uint8_t PORTE;
#endif
#ifndef PORTF
static uint8_t PORTF;
#endif
#ifndef PORTG
static uint8_t PORTG;
#endif
#ifndef PORTH
static uint8_t PORTH;
#endif
#ifndef PORTI
static uint8_t PORTI;
#endif
#ifndef PORTJ
static uint8_t PORTJ;
#endif
#ifndef PORTK
static uint8_t PORTK;
#endif
#ifndef PORTL
static uint8_t PORTL;
#endif
#ifndef PORTM
static uint8_t PORTM;
#endif
#ifndef PORTN
static uint8_t PORTN;
#endif
#ifndef PORTO
static uint8_t PORTO;
#endif
#ifndef PORTP
static uint8_t PORTP;
#endif
#ifndef PORTQ
static uint8_t PORTQ;
#endif
#ifndef PORTR
static uint8_t PORTR;
#endif
#ifndef PORTS
static uint8_t PORTS;
#endif
#ifndef PORTT
static uint8_t PORTT;
#endif
#ifndef PORTU
static uint8_t PORTU;
#endif
#ifndef PORTV
static uint8_t PORTV;
#endif
#ifndef PORTW
static uint8_t PORTW;
#endif
#ifndef PORTX
static uint8_t PORTX;
#endif
#ifndef PORTY
static uint8_t PORTY;
#endif
#ifndef PORTZ
static uint8_t PORTZ;
#endif
 
class bitset{
public:
    static constexpr auto size = 32;
 
    constexpr bitset(){}
    constexpr bitset(unsigned shift,unsigned port){ data[port] = (1<<shift);}
    constexpr bitset operator | (const bitset&value) const {
        bitset res;
        for(unsigned pos=0; pos<size; ++pos)
            res.data[pos] = data[pos] | value.data[pos];
        return res;
    }
    constexpr uint8_t getByte(size_t pos) const { return data[pos]; }
private:
    uint8_t data[size] = {0};
};
 
constexpr bitset operator "" _pin(const char*str, size_t){
    return bitset (str[1]-'0',str[0]-'A');
}
 
constexpr bitset segmentA="A3"_pin;
constexpr bitset segmentB="D1"_pin;
constexpr bitset usedBits=segmentA|segmentB;
 
template<unsigned port>
uint8_t getMask(unsigned number){
    static const uint8_t data[10]={
        (segmentA|segmentB).getByte(port),
        segmentA.getByte(port),
        segmentB.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port),
        segmentA.getByte(port)
    };
    return data[number];
}
 
template<unsigned portNumber,typename PortType>
inline void showNumber(unsigned number,PortType&port)
{
    if(usedBits.getByte(portNumber))
        port=(port&~usedBits.getByte(portNumber))|getMask<portNumber>(number);
}
 
template<unsigned portNumber,typename PortType,typename...Args>
inline void showNumber(unsigned number,PortType&port,Args&...args){
    if(usedBits.getByte(portNumber))
        port=(port&~usedBits.getByte(portNumber))|getMask<portNumber>(number);
    showNumber<portNumber+1,Args...>(number,args...);
}
 
inline void showNumber(unsigned number){
    showNumber<0>(number,
                  PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH,
                  PORTI, PORTJ, PORTK, PORTL, PORTM, PORTN, PORTO, PORTP,
                  PORTQ, PORTR, PORTS, PORTT, PORTU, PORTV, PORTW, PORTX,
                  PORTY, PORTZ
                 );
}
 
int main(){
  showNumber(0);
}
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Предлагаю эксперимент: я немного допиливаю ваш код, чтобы он нормально собирался (я так понял, у вас компилятора под AVR нет, так что мне это проще), после чего создаем в разделе AVR соответствующую тему с просьбой оценить оба варианта: какой покажется народу более простым и каким бы они предпочли пользоваться.
Уже допилил выше. Ну, можем людей поспрашивать. Но сомневаюсь что знакомому с C++ человеку будет удобней разбираться в хитросплетениях рекурсивных инклудов.

Добавлено через 33 минуты
Цитата Сообщение от Renji Посмотреть сообщение
Посмотрел ассемблерный листинг, сказал "что за фигня?" и ручками прописал inline.
UPD А, стоп, оно так вообще работу с массивом убирает, просто подставляя нужную константу. Заменил showNumber(0); на showNumber(x);, x задал как volatile unsigned x=0;, получилось 170 байт. Внимательно посмотрел в ассемблерный листинг, сказал "что за фигня?" еще раз. Туда все равно пролезло sts _ZL5PORTA,r18 записывающее значения в никем не используемую заглушку.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
    lds r24,x
    lds r25,x+1
    lds r18,_ZL5PORTA
    andi r18,lo8(-9)
    movw r30,r24
    subi r30,lo8(-(_ZZ7getMaskILj0EEhjE4data))
    sbci r31,hi8(-(_ZZ7getMaskILj0EEhjE4data))
    ld r19,Z
    or r18,r19
    sts _ZL5PORTA,r18//это зачем и для кого?
    in r18,0xb
    andi r18,lo8(-3)
    movw r30,r24
    subi r30,lo8(-(_ZZ7getMaskILj3EEhjE4data))
    sbci r31,hi8(-(_ZZ7getMaskILj3EEhjE4data))
    ld r25,Z
    mov r24,r18
    or r24,r25
    out 0xb,r24
    ldi r24,0
    ldi r25,0
    ret
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
23.08.2019, 17:13
Цитата Сообщение от Renji Посмотреть сообщение
В задаче "решить на новом языке" изучение нового языка идет по умолчанию.
Вот только вы не учитываете, что среди неявных условий задачи есть куча кода, написанного кем-то и зачем-то на Си, и есть разработчики, которые уже умеют писать на Си (как более простом языке) и перед которыми стоит выбор стоит ли переходить на С++, даст ли он существенные преимущества.
Цитата Сообщение от Renji Посмотреть сообщение
Поставил, avr-компилятор, покрутил.
Здесь меня смущает 1 байт оперативки. Интересно, под что он используется. А, все, понял. У вас segmentA был назначен на PORTA, которого в ATmega8 нет. Соответственно, заглушка не была выкинута и использовалась вместо настоящего порта. Кстати, это косяк вашего кода в текущем варианте: нет контроля ошибки. Если переназначить на другой порт, размер кода уменьшился до 70 байт, а оперативки - до нуля. Вот это уже красивый результат.
Вот только при попытке передать в функцию переменную (иначе какой смысл от такой функции?) размер кода вырос до:
C++
1
2
3
constexpr bitset segmentA="B3"_pin;
...
showNumber( PINB );
Code
1
2
3
4
5
Program:     146 bytes
(.text + .data + .bootloader)
 
Data:         20 bytes
(.data + .bss + .noinit)
Забавно, что вариант, который допиливал я и который показал 130 байт, вообще не отреагировал на замену константы переменной, так что лучше, наверное, его и использовать.
Цитата Сообщение от Renji Посмотреть сообщение
Уже допилил выше.
Я имел в виду допилить полностью, чтобы можно было скомпилировать под реальную схему и увидеть обратный отсчет. Скажем, нормальной разбивки на сегменты у вас все еще нет. Не поймите неправильно: мне для понимания идеи это не критично, но вот показывать посторонним стоит именно законченную и работоспособную версию. И надо будет что-то придумать с неправильным назначением портов.
Еще для законченной библиотеки важно настроить все порты на выход (DDRx = 1). Поскольку настройка выполняется единственный раз, особых требований к скорости тут нет. И если разбивку на сегменты в вашем коде я еще решусь делать, то вот работу с DDR'ами лучше оставлю вам. Ну и до кучи: возможно, стоит оформить ваш вариант в виде класса: это более в стиле С++, а если объект будет глобальным, оверхеда быть не должно.
Конечно, в моей версии с этим тоже все довольно плохо: оно плюется сотней ошибок на разные макросы и понять, что дело именно в портах, непросто. Но хотя бы не собирает заведомо неправильный код.
Цитата Сообщение от Renji Посмотреть сообщение
Расходы памяти сократились в десять раз.
Все же со 130 до 94 и даже до 70 это не в 10 раз. А учитывая, что оно странно себя ведет с переменной в качестве аргумента, лучше остановиться на 130-байтной версии.
Цитата Сообщение от Renji Посмотреть сообщение
Ну, можем людей поспрашивать. Но сомневаюсь что знакомому с C++ человеку будет удобней разбираться в хитросплетениях рекурсивных инклудов.
Вот и узнаем! Но сразу хочу предупредить о том, с чего начали: обычно под контроллеры пишут на Си, соответственно у Си-шного кода изначально будет небольшое преимущество в глазах общественности.

Добавлено через 1 минуту
UPD: что-то долго я ответ писал, еще до того, как вы дополнили свой пост. Ну да ладно
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
23.08.2019, 20:17
Собственно, более-менее финальная версия семисегментника на макросах. Добавил проверки настроек (оно и без них выдавало ошибки, но уж больно много - теперь причесал), добавил немного комментариев и прочие свистелки.
Отчасти делаю для себя же,чтобы не потерялось.
Вложения
Тип файла: rar 7seg_2.rar (4.0 Кб, 27 просмотров)
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.08.2019, 22:21
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Все же со 130 до 94 и даже до 70 это не в 10 раз. А учитывая, что оно странно себя ведет с переменной в качестве аргумента, лучше остановиться на 130-байтной версии.
Я про секцию data, которая от агрессивных инлайнов может опустеть.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Кстати, это косяк вашего кода в текущем варианте: нет контроля ошибки.
Ну, плюс static_assert и окончательное оформление портов как класса.
ports.h . Собственно, интерфейс для работы с портами.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef PORTS_H
#define PORTS_H
#include <avr/pgmspace.h>
#include<stdint.h>
//класс описывающий один порт
class PortDescriptor
{
public:
    //отображенный в память порт
    volatile uint8_t*port;
    //соответствующий ему DDR-регистр
    volatile uint8_t*ddr;
    //есть ли такой порт вообще. Нужно для static_assert, который не захотел кушать указатели выше
    bool exist;
};
 
//список портов
constexpr PortDescriptor portList[]={
    #ifndef PORTA
    {nullptr,nullptr,false},
    #else
    {&PORTA,&DDRA,true},
    #endif
    #ifndef PORTB
    {nullptr,nullptr,false},
    #else
    {&PORTB,&DDRB,true},
    #endif
    #ifndef PORTC
    {nullptr,nullptr,false},
    #else
    {&PORTC,&DDRC,true},
    #endif
    #ifndef PORTD
    {nullptr,nullptr,false},
    #else
    {&PORTD,&DDRD,true},
    #endif
    #ifndef PORTE
    {nullptr,nullptr,false},
    #else
    {&PORTE,&DDRE,true},
    #endif
    #ifndef PORTF
    {nullptr,nullptr,false},
    #else
    {&PORTF,&DDRF,true},
    #endif
    #ifndef PORTG
    {nullptr,nullptr,false},
    #else
    {&PORTG,&DDRG,true},
    #endif
    #ifndef PORTH
    {nullptr,nullptr,false},
    #else
    {&PORTH,&DDRH,true},
    #endif
    #ifndef PORTI
    {nullptr,nullptr,false},
    #else
    {&PORTI,&DDRI,true},
    #endif
    #ifndef PORTJ
    {nullptr,nullptr,false},
    #else
    {&PORTJ,&DDRJ,true},
    #endif
    #ifndef PORTK
    {nullptr,nullptr,false},
    #else
    {&PORTK,&DDRK,true},
    #endif
    #ifndef PORTL
    {nullptr,nullptr,false},
    #else
    {&PORTL,&DDRL,true},
    #endif
    #ifndef PORTM
    {nullptr,nullptr,false},
    #else
    {&PORTM,&DDRM,true},
    #endif
    #ifndef PORTN
    {nullptr,nullptr,false},
    #else
    {&PORTN,&DDRN,true},
    #endif
    #ifndef PORTO
    {nullptr,nullptr,false},
    #else
    {&PORTO,&DDRO,true},
    #endif
    #ifndef PORTP
    {nullptr,nullptr,false},
    #else
    {&PORTP,&DDRP,true},
    #endif
    #ifndef PORTQ
    {nullptr,nullptr,false},
    #else
    {&PORTQ,&DDRQ,true},
    #endif
    #ifndef PORTR
    {nullptr,nullptr,false},
    #else
    {&PORTR,&DDRR,true},
    #endif
    #ifndef PORTS
    {nullptr,nullptr,false},
    #else
    {&PORTS,&DDRS,true},
    #endif
    #ifndef PORTT
    {nullptr,nullptr,false},
    #else
    {&PORTT,&DDRT,true},
    #endif
    #ifndef PORTU
    {nullptr,nullptr,false},
    #else
    {&PORTU,&DDRU,true},
    #endif
    #ifndef PORTV
    {nullptr,nullptr,false},
    #else
    {&PORTV,&DDRV,true},
    #endif
    #ifndef PORTW
    {nullptr,nullptr,false},
    #else
    {&PORTW,&DDRW,true},
    #endif
    #ifndef PORTX
    {nullptr,nullptr,false},
    #else
    {&PORTX,&DDRX,true},
    #endif
    #ifndef PORTY
    {nullptr,nullptr,false},
    #else
    {&PORTY,&DDRY,true},
    #endif
    #ifndef PORTZ
    {nullptr,nullptr,false},
    #else
    {&PORTZ,&DDRZ,true},
    #endif
};
#endif // PORTS_H
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include<stddef.h>
#include"ports.h"
 
class bitset{
public:
    static constexpr auto size = 32;
 
    constexpr bitset(){}
    constexpr bitset(unsigned shift,unsigned port){ data[port] = (1<<shift);}
    constexpr bitset operator | (const bitset&value) const {
        bitset res;
        for(unsigned pos=0; pos<size; ++pos)
            res.data[pos] = data[pos] | value.data[pos];
        return res;
    }
    constexpr uint8_t getByte(size_t pos) const { return data[pos]; }
private:
    uint8_t data[size] = {0};
};
 
constexpr bitset operator "" _pin(const char*str, size_t){
    return bitset (str[1]-'0',str[0]-'A');
}
 
//настройки выводимых сегментов. Буква - порт, число - ножка в порте
constexpr bitset segmentA="B0"_pin;
constexpr bitset segmentB="B1"_pin;
constexpr bitset segmentC="B2"_pin;
constexpr bitset segmentD="B3"_pin;
constexpr bitset segmentE="C0"_pin;
constexpr bitset segmentF="C1"_pin;
constexpr bitset segmentG="C2"_pin;
//все использованные выше порты и ножки
constexpr bitset usedBits=segmentA|segmentB|segmentC|segmentD|segmentE|segmentF|segmentG;
 
//возвращает маску которую для цифры number нужно отправить в порт port
template<unsigned port>
uint8_t getMask(unsigned number){
    //каждый элемент массива - маска из представляющих одну цифру сегментов
    static const uint8_t data[10]={
        (segmentA|segmentB|segmentC|segmentD|segmentE|segmentF).getByte(port),//0
        (segmentB|segmentC).getByte(port),//1
        (segmentA|segmentB|segmentD|segmentE|segmentG).getByte(port),//2
        (segmentA|segmentB|segmentC|segmentD|segmentG).getByte(port),//3
        (segmentB|segmentC|segmentF|segmentG).getByte(port),//4
        (segmentA|segmentC|segmentD|segmentF|segmentG).getByte(port),//5
        (segmentA|segmentC|segmentD|segmentE|segmentF|segmentG).getByte(port),//6
        (segmentA|segmentB|segmentC).getByte(port),//7
        (segmentA|segmentB|segmentC|segmentD|segmentE|segmentF|segmentG).getByte(port),//8
        (segmentA|segmentB|segmentC|segmentD|segmentF|segmentG).getByte(port)//9
    };
    return data[number];
}
 
//вывод числа в portNumber порт
template<unsigned portNumber>
inline void showNumber(unsigned number)
{
    constexpr auto usedBitsMask=usedBits.getByte(portNumber);
    //либо мы в такой порт ничего не выводим, либо такой порт должен существовать
    static_assert (!usedBitsMask || bool(portList[portNumber].exist),"");
    if(usedBitsMask)
    {
        auto&port=*portList[portNumber].port;
        port=(port&~usedBitsMask)|getMask<portNumber>(number);
    }
    //переходим к следующему порту
    showNumber<portNumber+1>(number);
}
template<>inline void showNumber<26>(unsigned){}//просто заглушка чтобы прервать рекурсию выше
inline void showNumber(unsigned number){showNumber<0>(number);}
 
//инициализация DDR
template<unsigned portNumber>
inline void DDRInit()
{
    if(usedBits.getByte(portNumber))
        *portList[portNumber].ddr|=usedBits.getByte(portNumber);
    DDRInit<portNumber+1>();
}
template<>inline void DDRInit<26>(){}
inline void DDRInit(){DDRInit<0>();}
 
volatile unsigned x=0;
int main()
{
    //первичная настройка DDR-портов
    DDRInit();
    //показ нужного числа
    showNumber(x);
}
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
24.08.2019, 11:40
Цитата Сообщение от Renji Посмотреть сообщение
Я про секцию data, которая от агрессивных инлайнов может опустеть.
Ей вообще плевать на инлайны, это ведь переменные в ОЗУ. Достаточно было перенести массив в PROGMEM как секция data усыхает до нуля, как ей и положено.
Еще позволил себе поменять тип аргумента с unsigned (16 бит) на uint8_t (8 бит):
Code
1
2
3
4
5
Program:     156 bytes
(.text + .data + .bootloader)
 
Data:          1 bytes
(.data + .bss + .noinit)
Добавлено через 2 часа 29 минут
Цитата Сообщение от Renji Посмотреть сообщение
main.cpp
А не подскажете, как в вашем варианте вынести библиотеку в отдельный файл, чтобы можно было не лазить в ее исходный код для изменения настроек?
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
24.08.2019, 11:56
Вот что у меня получилось после модификаций вашего кода. Проверил в Протеусе - вроде работает. Посмотрите что еще посчитаете нужным причесать.
Code
1
2
3
4
5
Program:     160 bytes
(.text + .data + .bootloader)
 
Data:          0 bytes
(.data + .bss + .noinit)
Да, если решитесь допиливать свои ports под практическое применение, стоит добавить еще PINx для ввода. Для нашей задачи это не нужно, но в своих макросах я подобное сделал и частенько пользуюсь.
Вложения
Тип файла: rar 7seg.rar (2.3 Кб, 3 просмотров)
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
24.08.2019, 16:31
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А не подскажете, как в вашем варианте вынести библиотеку в отдельный файл, чтобы можно было не лазить в ее исходный код для изменения настроек?
Можно унести все в шаблон параметризуемый настроечным строковым литералом. Правда, я не особо вник почему, но этот литерал надо объявлять отдельной переменной. templateName<text> компилятор кушает, конструкцией templateName<"text"> давится.
shownumber.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#ifndef SHOWNUMBER_H
#define SHOWNUMBER_H
#include<stddef.h>
#include"ports.h"
 
class bitset{
public:
    static constexpr auto size = 32;
 
    constexpr bitset(){}
    constexpr bitset(unsigned shift,unsigned port){ data[port] = (1<<shift);}
    constexpr bitset operator | (const bitset&value) const {
        bitset res;
        for(unsigned pos=0; pos<size; ++pos)
            res.data[pos] = data[pos] | value.data[pos];
        return res;
    }
    constexpr uint8_t getByte(size_t pos) const { return data[pos]; }
private:
    uint8_t data[size] = {0};
};
 
constexpr bitset operator "" _pin(const char*str, size_t){
    return bitset (str[1]-'0',str[0]-'A');
}
 
 
template<const char*segmentList,//семь сегментов в формате "буква порта номер ножки"
         unsigned portNumber//порт, в который осуществляет вывод данный шаблон
         >
class BaseShowNumber
{
public:
    static constexpr bitset makeBitset(const char*str){return bitset (str[1]-'0',str[0]-'A');}
 
    //возвращает маску которую для цифры number нужно отправить в portNumber порт
    static inline uint8_t getMask(uint8_t number)
    {
        //каждый элемент массива - маска из представляющих одну цифру сегментов
        static PROGMEM const uint8_t data[10]={
            (segmentA|segmentB|segmentC|segmentD|segmentE|segmentF).getByte(portNumber),//0
            (segmentB|segmentC).getByte(portNumber),//1
            (segmentA|segmentB|segmentD|segmentE|segmentG).getByte(portNumber),//2
            (segmentA|segmentB|segmentC|segmentD|segmentG).getByte(portNumber),//3
            (segmentB|segmentC|segmentF|segmentG).getByte(portNumber),//4
            (segmentA|segmentC|segmentD|segmentF|segmentG).getByte(portNumber),//5
            (segmentA|segmentC|segmentD|segmentE|segmentF|segmentG).getByte(portNumber),//6
            (segmentA|segmentB|segmentC).getByte(portNumber),//7
            (segmentA|segmentB|segmentC|segmentD|segmentE|segmentF|segmentG).getByte(portNumber),//8
            (segmentA|segmentB|segmentC|segmentD|segmentF|segmentG).getByte(portNumber)//9
        };
        return data[number];
    }
 
    //вывод числа в portNumber порт
    static inline void showNumber(uint8_t number)
    {
        constexpr auto usedBitsMask=usedBits.getByte(portNumber);
        //либо мы в такой порт ничего не выводим, либо такой порт должен существовать
        static_assert (!usedBitsMask || portList[portNumber].exist,"");
        if(usedBitsMask)
        {
            auto&port=*portList[portNumber].port;
            port=(port&~usedBitsMask)|getMask(number);
        }
        //переходим к следующему порту
        BaseShowNumber<segmentList,portNumber+1>::showNumber(number);
    }
 
    //инициализация DDR
    static inline void DDRInit()
    {
        if(usedBits.getByte(portNumber))
            *portList[portNumber].ddr|=usedBits.getByte(portNumber);
        BaseShowNumber<segmentList,portNumber+1>::DDRInit();
    }
 
    //настройки выводимых сегментов
    static constexpr bitset segmentA=makeBitset(segmentList);
    static constexpr bitset segmentB=makeBitset(segmentList+3);
    static constexpr bitset segmentC=makeBitset(segmentList+6);
    static constexpr bitset segmentD=makeBitset(segmentList+9);
    static constexpr bitset segmentE=makeBitset(segmentList+12);
    static constexpr bitset segmentF=makeBitset(segmentList+15);
    static constexpr bitset segmentG=makeBitset(segmentList+18);
    //все использованные выше порты и ножки
    static constexpr bitset usedBits=segmentA|segmentB|segmentC|segmentD|segmentE|segmentF|segmentG;
};
template<const char*segmentList>
class BaseShowNumber<segmentList,26>
{
public:
    static inline void DDRInit(){}
    static inline void showNumber(uint8_t){}
};
template<const char*segmentList>
void showNumber(uint8_t number){BaseShowNumber<segmentList,0>::showNumber(number);}
template<const char*segmentList>void DDRInit(){BaseShowNumber<segmentList,0>::DDRInit();}
#endif // SHOWNUMBER_H
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include"shownumber.h"
 
//семь сегментов в формате "буква порта номер ножки"
constexpr char segmentList[]="B0 B1 B2 B3 C0 C1 C2";
volatile unsigned x=0;
int main()
{
    //первичная настройка DDR-портов
    DDRInit<segmentList>();
    //показ нужного числа
    showNumber<segmentList>(x);
}
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,099
24.08.2019, 19:00
Создал тему. Ждем отзывов
[опрос] Об использовании С++ в контроллерах
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.08.2019, 19:00

std::vector<int> Что это за тип данных?
std::vector&lt;int&gt; indexes_1, indexes_2; // Used for homography Что это за тип данных?

Что значит (для сущности «вершина» создать новый тип данных)?
Задание такое: Написать функцию для вычисления площади треугольника на плоскости, заданного координатами вершин. (для сущности «вершина»...

Восьмибитный тип переменной (что за тип, но не BYTE и не CHAR?
Вроде давно занимаюсь программированием на С++, но встала проблема... Есть некий массив переменных имеющих 8 битный размер... без знака...

Объясните, что это: "static const uint32_t collisionCategory = 0x1 << 0"?
Встретил в одном туториале по SpriteKit следующую строчку static const uint32_t projectileCategory = 0x1 &lt;&lt; 0; Подскажите...

Как сделать тип данных или уже есть такой тип данных который состоит из всех печатыемых символов?
Как сделать тип данных или уже есть такой тип данных который состоит из всех печатыемых символов? Если есть то как он называется ?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
172
Ответ Создать тему
Новые блоги и статьи
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
Генератор паролей (вариант №4)
Maks 01.11.2026
После публикации 3-го варианта генератора паролей, разослал его своим коллегам (с целью оценки), в итоге были получены следующие рекомендации: 1. Вернуть возможность использования знаков | 1 l I;. . .
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru