Tencentos Tiny EVB MX板学习第一篇Hello_world解析
  T3ePrzbE0s17 2023年11月02日 60 0


关于TencentOS tiny 基础内核实验

本次介绍的是关于TencentOS tiny 基础内核实验 ——hello_world实验

#Tiny EVB 板拿到以后会有两个途径学习
[Tencentos Tiny官网](https://gitee.com/TencentOS/TencentOS-tiny)和公众号IOTCluB获取官方资料

TencentOS tiny官方开源仓下载源码,地址为: ​​https://github.com/Tencent/TencentOS-tiny​​ 进入 <TencentOS_tiny\board\TencentOS_tiny_EVB_MX_Plus\KEIL\hello_world> 目录,打开

TencentOS_tiny.uvprojx 工程

Tencentos Tiny EVB MX板学习第一篇Hello_world解析_腾讯云


:就可以编辑下载运行。官方给出运行结果:在 PC 的串口助手中可以看到 TencentOS tiny 的两个任务交替运行,打印消息并完成任务计数,如下图所示:

Tencentos Tiny EVB MX板学习第一篇Hello_world解析_物联网_02


当然它屏幕也显示了LOGO。但是作为要学习的小白,这就能打发我们吗?不行!!!

来一起看看运行原理——为啥打印这些,要怎么做到这些,懂做才懂改。

#一个从源头查起,main.c

Tencentos Tiny EVB MX板学习第一篇Hello_world解析_stm32_03


#主要看 int main函数:

board_init();   //板子初始化
printf("Welcome to TencentOS tiny\r\n"); //串口打印
osKernelInitialize(); // TOS Tiny kernel initialize TOS Tiny内核初始化
osThreadCreate(osThread(application_entry), NULL); // Create TOS Tiny task创建TOS Tiny任务
osKernelStart(); // Start TOS Tiny TOS Tiny开始

#先看board_init(); //板子初始化:
<TencentOS_tiny\board\TencentOS_tiny_EVB_MX_Plus\BSP\Src\mcu_onit.c>文件中44行左右有相关函数,这里我对它进行了简单标注方便阅读:

void board_init(void)
{
char *str = "TencentOS tiny"; //定义字符串

HAL_Init(); //HAL库初始化
SystemClock_Config(); //系统时钟配置
MX_GPIO_Init(); //GPIO配置
//MX_ADC1_Init(); //ADC初始化
//MX_DAC1_Init(); //DAC初始化
//MX_I2C1_Init(); //IIC初始化
//MX_LPUART1_UART_Init(); //串口1初始化
// MX_USART2_UART_Init(); //串口2初始化
MX_USART3_UART_Init(); //串口3初始化
MX_TIM6_Init(); //计时器6初始化
//MX_SPI1_Init(); //SPI1初始化
//MX_SPI3_Init(); //spi3初始化
//DHT11_Init(); //外设DHT11初始化
OLED_Init(); //OLED显示屏幕初始化
OLED_Clear(); //OLED清屏
OLED_ShowChinese(0,0,0); //OLED显示字体
OLED_ShowChinese(18,0,1);
OLED_ShowChinese(36,0,2);
OLED_ShowChinese(54,0,3);
OLED_ShowChinese(72,0,4);
OLED_ShowChinese(90,0,5);
OLED_ShowString(0,2,(uint8_t*)str,16); //调用字符串显示
}

去掉它注解掉的函数,就能很清晰的看出来它用了几种功能:GPIO配置,串口初始化,定时器初始化,OLED初始化与显示。
注:这里的初始化,就是对一些基础设置,跟STM32基础一致,网上资料较全,不在累述。而OLED显示部分,在这里显示字符串,跟串口打印函数相似:OLED_ShowString(X坐标,Y坐标,需要显示的字符串); OLED_ShowChinese(X坐标,Y坐标,显示的字体在字库的位置);
下面看看OLED_ShowChinese函数代码:
//显示汉字

void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t no)
{
uint8_t t,adder=0;
OLED_Set_Pos(x,y); //定位XY
for(t=0;t<16;t++)//打印
{
OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{
OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
adder+=1;
}
}

而Hzk字库在oleddfont.h中

{0x40,0x3C,0x10,0xFF,0x10,0x10,0x20,0x10,0x8F,0x78,0x08,0xF8,0x08,0xF8,0x00,0x00},
{0x02,0x06,0x02,0xFF,0x01,0x01,0x04,0x42,0x21,0x18,0x46,0x81,0x40,0x3F,0x00,0x00},/*"物",0*/
/* (16 X 16 , 宋体 )*/

{0x02,0xFE,0x92,0x92,0xFE,0x02,0x00,0x10,0x11,0x16,0xF0,0x14,0x13,0x10,0x00,0x00},
{0x10,0x1F,0x08,0x08,0xFF,0x04,0x81,0x41,0x31,0x0D,0x03,0x0D,0x31,0x41,0x81,0x00},/*"联",1*/
/* (16 X 16 , 宋体 )*/

{0x00,0xFE,0x02,0x22,0x42,0x82,0x72,0x02,0x22,0x42,0x82,0x72,0x02,0xFE,0x00,0x00},
{0x00,0xFF,0x10,0x08,0x06,0x01,0x0E,0x10,0x08,0x06,0x01,0x4E,0x80,0x7F,0x00,0x00},/*"网",2*/
/* (16 X 16 , 宋体 )*/

{0x00,0x80,0x60,0xF8,0x07,0x00,0xFE,0x52,0x52,0x52,0x52,0x52,0xFE,0x00,0x00,0x00},
{0x01,0x00,0x00,0xFF,0x08,0x88,0x4F,0x29,0x09,0x09,0x09,0x29,0x4F,0x88,0x08,0x00},/*"俱",3*/
/* (16 X 16 , 宋体 )*/

{0x00,0x00,0xE0,0x9C,0x84,0x84,0x84,0xF4,0x82,0x82,0x83,0x82,0x80,0x80,0x00,0x00},
{0x00,0x20,0x10,0x08,0x06,0x40,0x80,0x7F,0x00,0x00,0x02,0x04,0x08,0x30,0x00,0x00},/*"乐",4*/
/* (16 X 16 , 宋体 )*/

{0x40,0x44,0x54,0x65,0x46,0x44,0x64,0x54,0x44,0x40,0xFE,0x02,0x22,0xDA,0x06,0x00},
{0x00,0x00,0x7E,0x22,0x22,0x22,0x22,0x7E,0x00,0x00,0xFF,0x08,0x10,0x08,0x07,0x00},/*"部",5*/
/* (16 X 16 , 宋体 )*/

可设置里面数组用工具(PctoLCD2002网上可免费下载)取模;
现在为止,屏幕显示已经明确,分析完 board_init();函数。
printf(“Welcome to TencentOS tiny\r\n”); //串口打印
就是让串口打印字符串

那么 osKernelInitialize(); 内核初始化做了什么?

Cmsis_os.c (osal\cmsis_os)中 :

osStatus osKernelInitialize(void)
{
return errno_knl2cmsis(tos_knl_init());
}

同样Cmsis_os.c (osal\cmsis_os)中:

static osStatus errno_knl2cmsis(k_err_t err)
{
return err == K_ERR_NONE ? osOK : osErrorOS; 返回 K_ERR_NONE 是否错误?是:否
}

就是反馈K_ERR_NONE 变量是否异常。
#osThreadCreate(osThread(application_entry), NULL); // Create TOS Tiny task
Cmsis_os.c (osal\cmsis_os)中:

/**

*@brief创建一个线程并将其添加到活动线程,然后将其设置为state READY。

*@param[in]thread \u def用osThread引用的线程定义。

*@param[in]参数指针,作为开始参数传递给线程函数。

*@return thread ID供其他函数引用,出错时返回NULL。

*/ 调用数组线程,将数据传给线程 *argument->*thread_def
osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument)
{
k_err_t err;

if (!thread_def) {
return NULL;
}

#if TOS_CFG_TASK_DYNAMIC_CREATE_EN > 0u //TOS_CFG_TASK_DYNAMIC_CREATE_EN = 0u
if (!thread_def->stackbase && !thread_def->task) {
k_task_t *task;
err = tos_task_create_dyn(&task, thread_def->name, (k_task_entry_t)thread_def->pthread,
argument, priority_cmsis2knl(thread_def->tpriority),
thread_def->stacksize, thread_def->timeslice);
return err == K_ERR_NONE ? task : NULL;
}
#endif //error

err = tos_task_create((k_task_t *)thread_def->task, thread_def->name, (k_task_entry_t)thread_def->pthread,
argument, priority_cmsis2knl(thread_def->tpriority), thread_def->stackbase,
thread_def->stacksize, thread_def->timeslice);

return err == K_ERR_NONE ? thread_def->task : NULL;
}

而之中变量osThread(application_entry)

#define osThread(name)  \
&os_thread_def_##name ##把&os_thread_def_和name连接起来,相当于&os_thread_def_name变量

application_entry函数在Hello_world.c (examples\hello_world):中:

void application_entry(void *arg)
{
printf("***I am task\r\n");
osThreadCreate(osThread(task1), NULL); // Create task1
osThreadCreate(osThread(task2), NULL); // Create task2
}

同文件中

#define TASK1_STK_SIZE          1024
void task1(void *arg);
osThreadDef(task1, osPriorityNormal, 1, TASK1_STK_SIZE);

#define TASK2_STK_SIZE 1024
void task2(void *arg);
osThreadDef(task2, osPriorityNormal, 1, TASK2_STK_SIZE);

#关于osThreadDef(name, priority, instances, stacksz)定义如下:

#define osThreadDef(name, priority, instances, stacksz)  \
k_task_t task_handler_##name; \
k_stack_t task_stack_##name[(stacksz)]; \
const osThreadDef_t os_thread_def_##name = \
{ #name, (os_pthread)(name), (osPriority)(priority), (instances), \
(&((task_stack_##name)[0])), (stacksz), ((k_timeslice_t)0u), (&(task_handler_##name)) }

总体总结为:创建结构体,给结构体命名,重装初值
而task函数为:

void task1(void *arg)
{
#if TOS_CFG_TASK_DYNAMIC_CREATE_EN > 0u
osThreadId task_dyn_created;

osThreadDynamicDef(task3, osPriorityNormal, 1, TASK3_STK_SIZE);
task_dyn_created = osThreadCreate(osThread(task3), NULL);

int count = 0;
#endif

while (1) {
printf("###I am task1\r\n");
osDelay(2000);

#if TOS_CFG_TASK_DYNAMIC_CREATE_EN > 0u
if (count++ == 3) {
printf("###I am task1, kill the task3(dynamic created)\r\n");
osThreadTerminate(task_dyn_created);
}
#endif
}
}

除去判断功能就是为了 printf("###I am task1\r\n"); 输出;
而且在main函数中

extern void application_entry(void *arg); //引用函数名
osThreadDef(application_entry, osPriorityNormal, 1, APPLICATION_TASK_STK_SIZE);//从做结构体

#最后一句 osKernelStart(); // Start TOS Tiny
// ==== Kernel Control Functions ====

osStatus osKernelStart(void)
{
return errno_knl2cmsis(tos_knl_start());
} //开启

与内核初始化相同,是一种判断返回。

本文用代码反推形式说明功能实现,具体修改相应的修改可以进行两个地方的简单修改:
1、把腾讯的LOGO改掉,用字库软件从新生成字符库。在oleddfont.h的Hzk[]的库中
2、把打印数据改掉,可以直接改在Hello_world.c (examples\hello_world):的task函数中: printf("###I am task1\r\n");
两种数据传出方式,为之后的传感器传出数据建立基础。

小白学习大神望指点,指出错误共同学习


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  JBfJ5LpBD0AJ   2023年11月13日   28   0   0 初始化链表#define
T3ePrzbE0s17