CAN总线踩坑记录

前言

最近负责的一个项目用的主控芯片是 STM32F407IGT6 ,需要和几个电机控制器进行通讯,有很多参数需要进行监控。 有一个问题一直无法解决。在开启 CAN 的接收中断,接收不到数据,问题卡了很久,下面简单分享一下解决的过程和思路。

lvgl8.3.5版本 设置界面滚动条显示状态

滚动条状态

LV_SCRLBAR_MODE_OFF 一直都不显示滚动条

LV_SCRLBAR_MODE_ON 一直都显示滚动条

LV_SCRLBAR_MODE_DRAG 拖动页面时显示滚动条

LV_SCRLBAR_MODE_AUTO 当可滚动容器的大小足以滚动时显示滚动条

LV_SCRLBAR_MODE_HIDE 暂时隐藏滚动条

LV_SCRLBAR_MODE_UNHIDE 取消隐藏以前隐藏的滚动条。也恢复原始模式

LVGL8的flex grow(弹性增长)使用方法

Flex(弹性布局) 描述

flex grow(弹性增长)

原理网上大把,我们直接说重点:

1
2
3
4
5
6
7
8
 LV_FLEX_FLOW_ROW 				  //将子元素排成一排而不包裹
 LV_FLEX_FLOW_COLUMN 			  //将子项放在一列中而不换行
 LV_FLEX_FLOW_ROW_WRAP 			  //将孩子排成一排并包裹起来 (超出部分换行)
 LV_FLEX_FLOW_COLUMN_WRAP 		  //将子元素放置在带有环绕的列中 (超出部分换列)
 LV_FLEX_FLOW_ROW_REVERSE 		  //将子元素排成一行而不换行,但顺序相反
 LV_FLEX_FLOW_COLUMN_REVERSE 	  //将子项放在一列中,不换行,但顺序相反
 LV_FLEX_FLOW_ROW_WRAP_REVERSE 	  //将子元素排成一行而不换行,但顺序相反
 LV_FLEX_FLOW_COLUMN_WRAP_REVERSE //将子项放在一列中,不换行,但顺序相反

关键代码

1
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);        // 设置对象容器使用基于行的流失弹性布局flex

举个例子

举例代码1

 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
void lv_demonstrate_flex_grow()
{
    lv_obj_t * cont = lv_obj_create(lv_scr_act()); // 基于屏幕创建一个cont容器对象
    if (cont == NULL)
    {
        return;
    }
 
    lv_obj_set_size(cont, 400, 220); // 设置对象大小
    lv_obj_center(cont); // 对象显示在屏幕中央
    lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); // 设置对象弹性布局的排列方式,把子对象排成一行,而不需要包裹
 
    lv_obj_t * obj = NULL;
    obj = lv_obj_create(cont);
    if (obj != NULL)
    {
        lv_obj_set_size(obj, 20, 40); // 设置对象大小
    }
 
    obj = lv_obj_create(cont);
    if (obj != NULL)
    {
        lv_obj_set_height(obj, 40); // 设置对象高度
        lv_obj_set_flex_grow(obj, 1);  // 宽度弹性增长,使用一份的剩余空间
    }
 
    obj = lv_obj_create(cont);
    if (obj != NULL)
    {
        lv_obj_set_height(obj, 40);
        lv_obj_set_flex_grow(obj, 2);   // 宽度弹性增长,使用2份的剩余空间
    }
 
    obj = lv_obj_create(cont);
    if (obj != NULL)
    {
        lv_obj_set_height(obj, 40);
        lv_obj_set_flex_grow(obj, 3);   // 宽度弹性增长,使用3份的剩余空间
    }
 
    obj = lv_obj_create(cont);
    if (obj != NULL)
    {
        lv_obj_set_size(obj, 40, 40);
    }
}

举例代码2

各个btn子元素间距均匀分部,和每行子元素底部对齐,两边距离容器边框25个像素,子元素的区域位置向容器中心对齐,并均匀分部。

C语言动态分配内存实现字符串格式化拼接

需求描述

这两天的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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
 
 
int str_append_to_string(char **str, const char *fmt, ...) 
{
	int ret = 0;
    char *ptr = NULL;
    va_list args;
    int limit_size = 0;
    static int init_size = 256;
    static int use_size = 0;
    int size = 0;
    int append_ok = 0;
 
    if (fmt == NULL || strlen(fmt) <= 0)
    {
        printf("[%s:%d] param error\n", __FUNCTION__, __LINE__);
        return -1;
    }
 
    ptr = *str;
    if (ptr == NULL)
    {
        ptr = (char *)malloc(init_size * sizeof(char));
        if (ptr == NULL)
        {
            printf("[%s:%d] malloc failed\n", __FUNCTION__, __LINE__);
            return -1;
        }
        
        init_size = 256;
        use_size = 0;
        memset(ptr, 0, (init_size * sizeof(char)));
    }
 
    do
    {
        limit_size = init_size - use_size - 1;
 
        va_start(args, fmt);
        size = vsnprintf((ptr + use_size), limit_size, fmt, args);
        va_end(args);
 
        if (size > 0 && size <= limit_size)
        {
            use_size += size;
            append_ok = 1;
            continue;
        }
 
        // need more memory
        init_size += init_size >> 2;
		char *ptr_backup = ptr; // 备份ptr指针
        ptr = (char *)realloc(ptr, init_size * sizeof(char)); // realloc失败的话ptr之前malloc的内存是不会被释放的
        if (ptr == NULL)
        {
            printf("[%s:%d] realloc failed\n", __FUNCTION__, __LINE__);
			ptr = ptr_backup; // 还原ptr指针
            ret = -1;
			break;
        }
    } while(!append_ok);
 
    *str = ptr;
 
    return ret;
}

调用代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int main(int argc, char*argv[])
{
	int ret = -1;
	char *string = NULL;
	ret = str_append_to_string(&string, "letters/%s/id_card/%d/name/%s", "ABC", 123, "Bob");
	if (ret == 0)
    {
		printf("string:%s\n", string);
	}
	
    if (string != NULL)
    {
		free(string);
		string = NULL;
    }
 
	return 0;
}

C语言实现通用链表

需求

相信很多项目中用动态内存来管理数据的时候会有用到链表,这比数组等方式方便多了。

网上收集的一个C语言双向链表,适合嵌入式等环境使用。

代码实现

C语言实现的双向通用链表,代码如下:

XAMPP的MySQL数据库无法启动的解决方案

由于电脑强制关机,当我第二次启动的时候,数据库就无法启动了,界面上报下面的错误

错误信息

1
2
3
4
5
6
7
8
15:26:52  [mysql] 	Error: MySQL shutdown unexpectedly.
15:26:52  [mysql] 	This may be due to a blocked port, missing dependencies, 
15:26:52  [mysql] 	improper privileges, a crash, or a shutdown by another method.
15:26:52  [mysql] 	Press the Logs button to view error logs and check
15:26:52  [mysql] 	the Windows Event Viewer for more clues
15:26:52  [mysql] 	If you need more help, copy and post this
15:26:52  [mysql] 	entire log window on the forums
15:27:21  [mysql] 	Status change detected: running

问题定位

查看了错误日志,无法看到任何报错信息。

MFC定时器Timer的使用

mfc的定时器功能,可以让程序周期性的执行一些功能。如定时采集数据,刷新界面等。我认为的好处,就是避免了使用多线程去实现那些功能。 下面介绍如何使用定时器Timer