Re: STM32, Atolic TrueStudio, CubeMX
Так от і мені цікаво — де
Так, щоб я прийшов додому після роботи, повечеряв, те-се, а тоді з 23:00 до 24:59 ще дві годинки поколупався у цікавим.
Аааа, в тому сенсі. Таки так. Є така проблема.
Ви не увійшли. Будь ласка, увійдіть або зареєструйтесь.
Ласкаво просимо вас на україномовний форум з програмування, веб-дизайну, SEO та всього пов'язаного з інтернетом та комп'ютерами.
Будемо вдячні, якщо ви поділитись посиланням на Replace.org.ua на інших ресурсах.
Для того щоб створювати теми та надсилати повідомлення вам потрібно Зареєструватись.
Український форум програмістів → Системне програмування → STM32, Atolic TrueStudio, CubeMX
Так от і мені цікаво — де
Так, щоб я прийшов додому після роботи, повечеряв, те-се, а тоді з 23:00 до 24:59 ще дві годинки поколупався у цікавим.
Аааа, в тому сенсі. Таки так. Є така проблема.
Я періодично, час від часу повертаюсь до цієї задачі і так і сяк, все ніяк не виходить.
Є така структура з бібліотеки 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 це вже не вказівники на окремий рядок меню, а на масив з пунктів меню - сторінки меню.
В принципі, я так розумію, що вказівник на масив, в цьому випадку, нічим не відрізняється від поодинокого пункту меню? Треба просто ще знати скільки елементів масиву треба обробити?
Що порадите? Вже максимально постарався пояснити що я хочу. Допоможіть будь ласочка.
Всім вітання.
Хочу для колег по залізниці зробити одну приблуду. Є стара телеграфна станція.
Треба мікроконтролером "ловити" коди MTK-2 з швидкістю 50 бод. Baud rate = 33.3 bit/s, Data bits = 5, Stop bit = 1.5
Я так розумію хардварний UART не підійде? Пробував на компі термінальною програмою "ловити" через COM порт з такими параметрами, але щось не вийшло. Може щось не правильно зробив. Тіко нулі ловить.
А якщо робити ногодригом звичайним, то як це реалізувати?
Думаю що треба якось типу так:
По старт біту починаємо відлік і через кожні 20 мс перевіряємо стан ніжки
Кладемо кожен стан до буферу
Після відліку 5 біт, складаємо в байт
Але це якось дуже просто, може статись якесь зміщення і вже буде спотворення прийому. Не враховується стоп біт. Він же ж не просто так існує. Чи може якісь є вже напрацьовані алгоритми?
Направте в потрібне русло. Дякую.
Всім вітання.
Хочу для колег по залізниці зробити одну приблуду. Є стара телеграфна станція.
Треба мікроконтролером "ловити" коди MTK-2 з швидкістю 50 бод. Baud rate = 33.3 bit/s, Data bits = 5, Stop bit = 1.5
Я так розумію хардварний UART не підійде? Пробував на компі термінальною програмою "ловити" через COM порт з такими параметрами, але щось не вийшло. Може щось не правильно зробив. Тіко нулі ловить.
А якщо робити ногодригом звичайним, то як це реалізувати?
Думаю що треба якось типу так:
По старт біту починаємо відлік і через кожні 20 мс перевіряємо стан ніжки
Кладемо кожен стан до буферу
Після відліку 5 біт, складаємо в байт
Але це якось дуже просто, може статись якесь зміщення і вже буде спотворення прийому. Не враховується стоп біт. Він же ж не просто так існує. Чи може якісь є вже напрацьовані алгоритми?
Направте в потрібне русло. Дякую.
Так думаю документації немає до того куди підключаєтеся. Спочатку радив би осцилографом подивитися що приймаєте. Потім логічним аналізатором спостерігав би сам обмін. А лиш потім думав про реалізацію.
Так думаю документації немає до того куди підключаєтеся.
Та є. Все зрозуміло, для мене, крім програмної реалізації.
Є стартовий біт 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мс до наступного знаку. Поки чекаємо стоп бітік, можна зібрати до купи бітікі в байтик звірити з таблицею кодування, та видати десь його далі чи покласти в буфер.
reverse2500 написав:Тільки там немає інфи про те як на рівні фізики то, куди підключається і т.д.
Декодування то остання проблема в цій історії.
фізично/електрично всьо вже є. Нічого складного. Через оптопару все приводиться до 3.3В логіки. ЛОГ.1 і ЛОГ.0 отримую.
Таку низьку частоту для USART можна буде виставити хіба знижуючи основну частоту, одних AHB prescaler і дільника USART не вистачть.
Якщо лише приймати, то 1.5 стоп-біти не турбують, розраховувати на один, а ще 0.5 буде просто пропуститься до наступного стартового спаду.
Але це все неважливо, в stm32f103 він у 5 бітів не вміє.
Програмно — спад, відступити 0.5 біта, перевірити, чи таки 0=старт, а не наводка.
Вже звідти по одному біту до стопа, стоп бажано теж перевірити, чи 1.
Зручно на таймері, що вільно біжить — capture, отримали момент старту і підготували всі лічильники, перемкнули на compare і додали ширину (спочатку пів біта, потім біт), по перериванню compare аналіз входу, після стопового біта знову на capture по спаду.
Алгоритм простий - кілька зарубок на кожному бiт «плаваючим вікном» + мажоритарна логіка http://raxp2.blogspot.com/2015/02/blog-post_7.html
Алгоритм простий - кілька зарубок на кожному бiт «плаваючим вікном» + мажоритарна логіка http://raxp2.blogspot.com/2015/02/blog-post_7.html
Дякую. Почитав. Цікаво. Теж думав робити декілька засічок на бітік. Спочатку спробую UART emulator від ST. Може софтовим UARTом вийде ловити МТК-2. Як ні, то вже буду такий спосіб задіювати.
Всім привіт.
Закортіло мені замутити "універсальну" 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 інтерфейс в коді, тоді все гаразд. Теж логічно.
Якщо я правильно зрозумів ви хочете проініціалізувати вказівник на структуру LCD_HandleTypeDef* hlcd, котру ви передаєте першим параметром функції lcdI2CInit, а наступні аргументи цієї функції є саме значеннями котрі повинні заповнити вищезгадану структуру. Оскільки другий аргумент теж вказівник на структуру, то він має вказувати на ділянку пам'яті у стеку, тобто коли компілюється код, під покажчик на цю структуру компілятор резервує для нього пам'ять і він вже має існувати коли передається другим аргументом у функції.
Або Ви повинні ініціалізувати в LCD_HandleTypeDef* hlcd показник на I2C_HandleTypeDef* hi2c ще до того, як передасте його аргументом функції lcdI2CInit, тобто I2C_HandleTypeDef* hi2c вже має вказувати на ділянку пам'яті.
Але захотілось зробити не правкою коду через передпроцесорні дерективи #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, просто додасиш інтерфейс.
Щиро дякую хлопці. Це неперевершено. Ідею зрозумів. Буду розбиратись.
(ой, я там таки позабував дещо, функції то мали повертати значення)
І ще
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);
}