181

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Так от і мені цікаво — де :D
Так, щоб я прийшов додому після роботи, повечеряв, те-се, а тоді з 23:00 до 24:59 ще дві годинки поколупався у цікавим.

Аааа, в тому сенсі. Таки так. Є така проблема.

182

Re: STM32, Atolic TrueStudio, CubeMX

Я періодично, час від часу повертаюсь до цієї задачі і так і сяк, все ніяк не виходить.

Є така структура з бібліотеки micromenu-2:

typedef const struct ItemMenu
{
    const struct ItemMenu *Parent;
    const struct ItemMenu *Child;
    void(*SelectCallback)(void);
    void(*EnterCallback) (void);
    const char Text[16];
    const char Value[16];
}ItemMenuStruct;

Цією бібліотекою я успішно користуюсь, але хочу дещо модифікувати

Мене зараз цікавлять поля Parent і Child. Це вказівник на попереднє меню та на наступне такої ж структури. А якщо я хочу вказати на масив з цих структур, що мені потрібно поміняти/додати в цій структурі?

Ну ось я оголосив два пункти меню:

ItemMenuStruct const Menu1 = {NULL_MENU, Menu2, NULL, NULL, "Menu-1", "->"};
ItemMenuStruct const Menu2 = {Menu1, NULL_MENU, NULL, NULL, "Menu-2", "<-"};

як тицьнути на один пункт меню, то викликається інший пункт меню і навпаки. Але це по одному пункту. А як я хочу цілий список з декількох рядків меню. Щось типу такого:

ItemMenuStruct const Menu1_1 = {NULL_MENU, Page2, NULL, NULL, "Enter page 2", "->"};
ItemMenuStruct const Menu1_2 = {NULL_MENU, NULL_MENU, NULL, func1_2, "Menu 1.2", "--"};
ItemMenuStruct const Menu1_3 = {NULL_MENU, NULL_MENU, NULL, func1_3, "Menu 1.3", "--"};
ItemMenuStruct const Menu1_4 = {NULL_MENU, NULL_MENU, NULL, func1_4, "Menu 1.4", "--"};
ItemMenuStruct const Menu1_5 = {NULL_MENU, NULL_MENU, NULL, func1_5, "Menu 1.5", "--"};

ItemMenuStruct const Page1[5] = {Menu1_1, Menu1_2, Menu1_3, Menu1_4, Menu1_5};

ItemMenuStruct const Menu2_1 = {Page1, NULL_MENU, NULL, NULL, "Return page 1", "<-"};
ItemMenuStruct const Menu2_2 = {NULL_MENU, NULL_MENU, NULL, func2_2, "Menu 2.2", "--"};
ItemMenuStruct const Menu2_2 = {NULL_MENU, NULL_MENU, NULL, func2_3, "Menu 2.3", "--"};

ItemMenuStruct const Page2[3] = {Menu2_1, Menu2_2, Menu2_3};

Перший пункт меню першої сторінки, це виклик другої сторінки меню. А інші пункти виклик якихось функцій. А на другій сторінці меню перший пункт, це перехід до першої сторінки меню, всі інші пункти виклик якихось функцій.
Іншими словами Parent та Child це вже не вказівники на окремий рядок меню, а на масив з пунктів меню - сторінки меню.
В принципі, я так розумію, що вказівник на масив, в цьому випадку, нічим не відрізняється від поодинокого пункту меню? Треба просто ще знати скільки елементів масиву треба обробити?

Що порадите? Вже максимально постарався пояснити що я хочу. Допоможіть будь ласочка.

183

Re: STM32, Atolic TrueStudio, CubeMX

Всім вітання.

Хочу для колег по залізниці зробити одну приблуду. Є стара телеграфна станція.
Треба мікроконтролером "ловити" коди MTK-2 з швидкістю 50 бод. Baud rate = 33.3 bit/s, Data bits = 5, Stop bit = 1.5
Я так розумію хардварний UART не підійде? Пробував на компі термінальною програмою "ловити" через COM порт з такими параметрами, але щось не вийшло. Може щось не правильно зробив. Тіко нулі ловить.
А якщо робити ногодригом звичайним, то як це реалізувати?
Думаю що треба якось типу так:

  • По старт біту починаємо відлік і через кожні 20 мс перевіряємо стан ніжки

  • Кладемо кожен стан до буферу

  • Після відліку 5 біт, складаємо в байт

Але це якось дуже просто, може статись якесь зміщення і вже буде спотворення прийому. Не враховується стоп біт. Він же ж не просто так існує. Чи може якісь є вже напрацьовані алгоритми?
Направте в потрібне русло. Дякую.

184

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Всім вітання.

Хочу для колег по залізниці зробити одну приблуду. Є стара телеграфна станція.
Треба мікроконтролером "ловити" коди MTK-2 з швидкістю 50 бод. Baud rate = 33.3 bit/s, Data bits = 5, Stop bit = 1.5
Я так розумію хардварний UART не підійде? Пробував на компі термінальною програмою "ловити" через COM порт з такими параметрами, але щось не вийшло. Може щось не правильно зробив. Тіко нулі ловить.
А якщо робити ногодригом звичайним, то як це реалізувати?
Думаю що треба якось типу так:

  • По старт біту починаємо відлік і через кожні 20 мс перевіряємо стан ніжки

  • Кладемо кожен стан до буферу

  • Після відліку 5 біт, складаємо в байт

Але це якось дуже просто, може статись якесь зміщення і вже буде спотворення прийому. Не враховується стоп біт. Він же ж не просто так існує. Чи може якісь є вже напрацьовані алгоритми?
Направте в потрібне русло. Дякую.

Так думаю документації немає до того куди підключаєтеся. Спочатку радив би осцилографом подивитися що приймаєте. Потім логічним аналізатором спостерігав би сам обмін. А лиш потім думав про реалізацію.

185

Re: STM32, Atolic TrueStudio, CubeMX

МТК-2

Подякували: leofun011

186 Востаннє редагувалося HetmanNet (27.11.2019 15:09:19)

Re: STM32, Atolic TrueStudio, CubeMX

reverse2500 написав:

МТК-2

Тільки там немає інфи про те як на рівні фізики то, куди підключається і т.д.
Декодування то остання проблема в цій історії.

Подякували: leofun011

187

Re: STM32, Atolic TrueStudio, CubeMX

HetmanNet написав:

Так думаю документації немає до того куди підключаєтеся.

Та є. Все зрозуміло, для мене, крім програмної реалізації.
Є стартовий біт 1*t0, потім п'ять бітів даних 5*t0, а потім 1,5*t0 стоп біта. Де t0 для 50 бод = 20мс.
Мене цікавить декілька питань:
Чи можна налаштувати хардварний UART на stm32 з такими параметрами Baud rate = 33.3 bit/s, Data bits = 5, Stop bit = 1.5?
Як не можна, то на пальцях алгоритм, як ловити то все софтово?
Собі уявляю, що треба по перериванню почати відлік в 20 мс + 10 мс, щоб попасти на середину бітіка і прочитати його стан, потім 4 рази по 20мс з читанням стану. А потім знову чекаємо 30мс до наступного знаку. Поки чекаємо стоп бітік, можна зібрати до купи бітікі в байтик звірити з таблицею кодування, та видати десь його далі чи покласти в буфер.

188

Re: STM32, Atolic TrueStudio, CubeMX

HetmanNet написав:
reverse2500 написав:

МТК-2

Тільки там немає інфи про те як на рівні фізики то, куди підключається і т.д.
Декодування то остання проблема в цій історії.

фізично/електрично всьо вже є. Нічого складного. Через оптопару все приводиться до 3.3В логіки. ЛОГ.1 і ЛОГ.0 отримую.

189

Re: STM32, Atolic TrueStudio, CubeMX

Таку низьку частоту для USART можна буде виставити хіба знижуючи основну частоту, одних AHB prescaler і дільника USART не вистачть.
Якщо лише приймати, то 1.5 стоп-біти не турбують, розраховувати на один, а ще 0.5 буде просто пропуститься до наступного стартового спаду.
Але це все неважливо, в stm32f103 він у 5 бітів не вміє.

Програмно — спад, відступити 0.5 біта, перевірити, чи таки 0=старт, а не наводка.
Вже звідти по одному біту до стопа, стоп бажано теж перевірити, чи 1.

Зручно на таймері, що вільно біжить — capture, отримали момент старту і підготували всі лічильники, перемкнули на compare і додали ширину (спочатку пів біта, потім біт), по перериванню compare аналіз входу, після стопового біта знову на capture по спаду.

Подякували: taburyak1

190

Re: STM32, Atolic TrueStudio, CubeMX

Алгоритм простий - кілька зарубок на кожному бiт «плаваючим вікном» + мажоритарна логіка http://raxp2.blogspot.com/2015/02/blog-post_7.html

Подякували: taburyak1

191

Re: STM32, Atolic TrueStudio, CubeMX

raxp написав:

Алгоритм простий - кілька зарубок на кожному бiт «плаваючим вікном» + мажоритарна логіка http://raxp2.blogspot.com/2015/02/blog-post_7.html

Дякую. Почитав. Цікаво. Теж думав робити декілька засічок на бітік. Спочатку спробую UART emulator від ST. Може софтовим UARTом вийде ловити МТК-2. Як ні, то вже буду такий спосіб задіювати.

192 Востаннє редагувалося taburyak (24.01.2021 12:03:24)

Re: STM32, Atolic TrueStudio, CubeMX

Всім привіт.
Закортіло мені замутити "універсальну" 4-х бітну + I2C бібліотеку для LCD1602. В принципі, цю бібліотеку я маю https://github.com/taburyak/LCD1602_I2C_OR_4BIT_STM32
Але захотілось зробити не правкою коду через передпроцесорні дерективи #define, а потім #ifndef та #ifdef і все таке. А заповнювати структуру через функції init. А потім ініціалізувати периферію відповідно. І в залежності від обраного інтерфейсу вже взаємодіяти з LCD.

Почав писати функцію ініціалізації LCD для варіанту з шиною I2C.

Структура:

typedef struct{
    TypeLCD_EnumTypeDef    type;
    InterfaceLCD_EnumTypeDef bus;
    I2C_HandleTypeDef* hi2c;
    uint8_t address;
    ParallelBusLCD_StructTypeDef pins;
}LCD_HandleTypeDef;

Прототип функції для шини I2C:

extern void lcdI2CInit(LCD_HandleTypeDef* hlcd, I2C_HandleTypeDef* hi2c, uint8_t address);

В функцію передаю вказівник структури LCD, вказівник структури для I2C і адресу на шині I2C. Далі в функції передбачається передати в струкуру LCD вказівник на структуру I2C і адресу I2C і далі вже взаємодіяти з LCD.

Але коли я LCD буду під'єднувати до мк паралельним інтерфейсом, то компілятор про I2C_HandleTypeDef знати не знає і не відає. Що логічно. Що робити в такому випадку? Щось не можу придумати. Мова Сі не Сі++.

Коли оголошую I2C інтерфейс в коді, тоді все гаразд. Теж логічно.

193 Востаннє редагувалося lucas-kane (24.01.2021 14:38:23)

Re: STM32, Atolic TrueStudio, CubeMX

Якщо я правильно зрозумів ви хочете проініціалізувати вказівник на структуру LCD_HandleTypeDef* hlcd, котру ви передаєте першим параметром функції lcdI2CInit, а наступні аргументи цієї функції є саме значеннями котрі повинні заповнити вищезгадану структуру. Оскільки другий аргумент теж вказівник на структуру, то він має вказувати на ділянку пам'яті у стеку, тобто коли компілюється код, під покажчик на цю структуру компілятор резервує для нього пам'ять і він вже має існувати коли передається другим аргументом у функції.

Прихований текст

Приклад коду ...

/* ... */

typedef unsigned char uint8_t;

// Тут, список змінних це абстрактні адреси. Щоб не копіювати лишній код ))
typedef struct {
    uint8_t ada; /* Для прикладу адреса А*/
    uint8_t adb; /* та адреса Б */
} I2C_HandleTypeDef;


/* ... */

typedef struct {
    /* ... */
    I2C_HandleTypeDef* hi2c;
    uint8_t address;
    /* ... */
} LCD_HandleTypeDef;

extern void lcdI2CInit(LCD_HandleTypeDef* hlcd, I2C_HandleTypeDef *hi2c, uint8_t address) {
    hlcd->hi2c = hi2c;     
    hlcd->address = address;
}

int main() {
    /* має існувати ще до того, коли буде передана до функції lcdI2CInit */
    I2C_HandleTypeDef hani2c = { 0x32, 0x33 }, *pi2c = &hani2c;
    LCD_HandleTypeDef hanLCD, *pLCD = &hanLCD;

    lcdI2CInit(pLCD, pi2c, 0x004f);

    return 0;
}
Подякували: taburyak1

194

Re: STM32, Atolic TrueStudio, CubeMX

Або Ви повинні ініціалізувати в LCD_HandleTypeDef* hlcd показник на I2C_HandleTypeDef* hi2c ще до того, як передасте його аргументом функції lcdI2CInit, тобто I2C_HandleTypeDef* hi2c вже має вказувати на ділянку пам'яті.

Подякували: taburyak1

195 Востаннє редагувалося ReAl (27.01.2021 10:51:47)

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Але захотілось зробити не правкою коду через передпроцесорні дерективи #define, а потім #ifndef та #ifdef і все таке.

Щоб поменше такого робити, придумали функції зворотного виклику у тому чи іншому вигляді
(а щоб поменше писати вручну описи структур функцій зворотного виклику, придумали C++, але то інша історія).

Драйвер власне LCD, який переміщує курсор, завантажує потрібні символи, виводить текст — може
(і має, при цих вимогах) нічого не знати про інтерфейс.
Вибираєш ти тип інтерфейсу коли підключаєш бібліотеку до конкретного проекту, тому в цьому проекті
можеш включити потрібні h-файли. Наприклад

#include "lcd1602_interface_i2c.h"
#include "lcd1602.h"

// створив інтерфейс через i2c
// користуєшся, не думаючи, який інтерфейс

Якимись такими шматками, сподіваюся, буде зрозуміло те, що я зараз напишу (щось мене хитає, чи то зміна погоди,
чи то овертайм протягом тижня + домашка-лабораторка сьогодні вранці, після якої вирубився зовсім).

// lcd1602.h

/* opaque -- LCD user does not know about internals */
typedef struct LCD_InterfaceHandle LCD_InterfaceHandleDef;

//  int умовно, для коду помилки
int lcdInit(LCD_InterfaceHandleDef *interface);
int lcdSetMode(LCD_InterfaceHandleDef *interface, uint8_t mode);
int lcdPutc(LCD_InterfaceHandleDef *interface, char ch);
/* ... */
// lcd1602_interface_i2c.h
LCD_InterfaceHandleDef *LCD_Interface_I2C_Create( /* bus number, address, ...*/);
void LCD_Interface_I2C_Destroy(LCD_InterfaceHandleDef *interface);
// lcd1602_interface_4bit.h
LCD_InterfaceHandleDef *LCD_Interface_4bit_Create( /* pin descriptor array */ );
void LCD_Interface_4bit_Destroy(LCD_InterfaceHandleDef *interface);
// lcd1602_internal.h
struct LCD_InterfaceHandle {
    int (*init_interface)(LCD_InterfaceHandleDef *interface);
    int (*out_cmd)(LCD_InterfaceHandleDef *interface, uint8_t cmd);
    int (*out_data)(LCD_InterfaceHandleDef *interface, uint8_t data);
    // driver private data starting point
    uint8_t driver_data[];
};
// I2C interface implementation
#include ... що там для I2C HAL

struct LCD_Interface_I2C_private {
    I2C_HandleTypeDef* hi2c;
    uint8_t address;
};

static int i2c_lcd_init_interface(LCD_InterfaceHandleDef *interface);
static int i2c_lcd_out_cmd(LCD_InterfaceHandleDef *interface, uint8_t cmd);
static int i2c_lcd_out_data(LCD_InterfaceHandleDef *interface, uint8_t data);

LCD_InterfaceHandleDef *LCD_Interface_I2C_Create( /* bus number, address, ...*/)
{
    LCD_InterfaceHandleDef *handle;
    struct LCD_Interface_I2C_private *priv;

    handle = malloc(sizeof(*handle) + sizeof(*priv));

    if (!handle)
        return NULL;

    priv = (struct LCD_Interface_I2C_private *)handle->data;

    handle->init_interface = i2c_lcd_init_interface;
    ...
    priv->address = address;
    ...

    return handle;
}

static int i2c_lcd_init_interface(LCD_InterfaceHandleDef *interface)
{
    struct LCD_Interface_I2C_private *priv = (struct LCD_Interface_I2C_private *)handle->data;
    ...
}
// LCD library implementation
static inline int init_interface(LCD_InterfaceHandleDef *interface)
{
    return interface->init_interface(interface);
}

static inline int out_cmd(LCD_InterfaceHandleDef *interface, uint8_t cmd)
{
    return interface->out_cmd(interface, cmd);
}

int lcdInit(LCD_InterfaceHandleDef *interface)
{
    // TODO: handle errors :-)
    // все про 4-бітну чи яку іншу шину там всередині
    init_interface(interface);

    // далі лише очищення екрану, потрібні режими, ...
    out_cmd(interface, ...);
    delay(,,,);
    out_cmd(interface, ...);

    ...
}

Швидше за все щось кудись треба буде між h-файлами перенести чи зробити ще один.
Схочеш додати SPI, просто додасиш інтерфейс.

Подякували: Betterthanyou, leofun01, taburyak3

196

Re: STM32, Atolic TrueStudio, CubeMX

Щиро дякую хлопці. Це неперевершено. Ідею зрозумів. Буду розбиратись.  *YAHOO*

197

Re: STM32, Atolic TrueStudio, CubeMX

(ой, я там таки позабував дещо, функції то мали повертати значення)

І ще

static inline int some_func(LCD_InterfaceHandleDef *interface, uint8_t cmd)
{
    return interface->some_func(interface, cmd);
}

тут не лише для того, щоб писати коротше some_func(interface, cmd); замість interface->some_func(interface, cmd);, а й для

static inline int some_func(LCD_InterfaceHandleDef *interface, uint8_t cmd)
{
    BUG_ON(interface->some_func == NULL); // implementation required

    return interface->some_func(interface, cmd);
}

або

static inline int some_func(LCD_InterfaceHandleDef *interface, uint8_t cmd)
{
    if(interface->some_func == NULL)
        return 0; // All ok, function is not implemented because it's not necessary

    return interface->some_func(interface, cmd);
}

або

static inline int some_func(LCD_InterfaceHandleDef *interface, uint8_t cmd)
{
    if(interface->some_func == NULL)
        return some_func_default(interface, cmd); // Default implementation is OK

    return interface->some_func(interface, cmd);
}