【ThreadX】ThreadX源码阅读计划(一)

目的

就是有那么一点好奇,能够通过SIL4级别安全认证的RTOS的代码到底有多厉害~~所以想来读一读
所有代码的解读均采用默认的配置,未使能的条件编译和不重要的注释就不解读了~

初始化部分

_tx_initialize_low_level

一个汇编函数

@
@    /* 关中断  */
@
    CPSID   i
@
@    /* 设置未初始化的可用内存区域的基地址 */
@
    /* _tx_initialize_unused_memory这个变量的地址给r0*/
    LDR     r0, =_tx_initialize_unused_memory       @ Build address of unused memory pointer
    /* __RAM_segment_used_end__这个变量的地址给r1*/
    LDR     r1, =__RAM_segment_used_end__           @ Build first free address
    /* r1=r1+4*/
    ADD     r1, r1, #4                              @
    /* 将r1寄存器的值,传送到地址值为r0的(存储器)内存中,其实也就是把你填的__RAM_segment_used_end__写到_tx_initialize_unused_memory变量里*/
    STR     r1, [r0]                                @ Setup first unused memory pointer
@
@    /* 设置向量表偏移寄存器  */
@
    MOV     r0, #0xE000E000                         @ Build address of NVIC registers
    /*现在的中断向量表的位置【0x8000000】复制到r1*/
    LDR     r1, =_vectors                           @ Pickup address of vector table
    /* 将R1中的字数据写入以R0+0xD08为地址的存储器中。【设置中断向量表偏移】 */
    STR     r1, [r0, #0xD08]                        @ Set vector table address
@
@    /* 从向量表的值设置系统堆栈指针. */
@
    /*_tx_thread_system_stack_ptr这个变量的地址给r0*/
    LDR     r0, =_tx_thread_system_stack_ptr        @ Build address of system stack pointer
    /*现在的中断向量表的位置【0x8000000】复制到r1*/
    LDR     r1, =_vectors                           @ Pickup address of vector table
    /*把中断向量表起始地址【0x8000000】对应的内存值读到r1中 */
    LDR     r1, [r1]                                @ Pickup reset stack pointer
    /*把上一步读到的复位堆栈指针的值【你在链接文件里设置的_estack】读到_tx_thread_system_stack_ptr里*/
    STR     r1, [r0]                                @ Save system stack pointer
@
@    /* Enable the cycle count register.  */
@
    /* 使能DWT功能 */
    LDR     r0, =0xE0001000                         @ Build address of DWT register
    /* 把当前的DWT计数值读到r1 */
    LDR     r1, [r0]                                @ Pickup the current value
    /* 将DWT寄存器中的CYCCNTENA位置为1 */
    ORR     r1, r1, #1                              @ Set the CYCCNTENA bit
    /* 将设置好的值设置到内核里 */
    STR     r1, [r0]                                @ Enable the cycle count register
@
@    /* 配置Systick为100Hz【10ms周期】*/
    /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference.  */
@
    MOV     r0, #0xE000E000                         @ Build address of NVIC registers
    LDR     r1, =SYSTICK_CYCLES                     @ SYSTICK_CYCLES是根据你的系统时钟决定的
    /*设置Systick重装值*/
    STR     r1, [r0, #0x14]                         @ Setup SysTick Reload Value
    /*给Systick最基础的设置 CLKSOURCE=1 TICKINT=1 ENABLE=1*/
    MOV     r1, #0x7                                @ Build SysTick Control Enable Value
    /*把写好的设置值写到对应的寄存器里面*/
    STR     r1, [r0, #0x10]                         @ Setup SysTick Control
@
@    /* 设置处理函数的优先级 */
@
    LDR     r1, =0x00000000                         @ Rsrv, UsgF, BusF, MemM
    /* Rsrv, UsgF, BusF, MemM异常处理函数的优先级 */
    STR     r1, [r0, #0xD18]                        @ Setup System Handlers 4-7 Priority Registers
    /* SVC1异常处理函数的优先级,它优先级最低 */
    LDR     r1, =0xFF000000                         @ SVCl, Rsrv, Rsrv, Rsrv
    STR     r1, [r0, #0xD1C]                        @ Setup System Handlers 8-11 Priority Registers
                                                    @ Note: SVC must be lowest priority, which is 0xFF
    /* SysTick,PendSV,DbgM的优先级,DbgM优先级最低 */
    LDR     r1, =0x40FF0000                         @ SysT, PnSV, Rsrv, DbgM
    STR     r1, [r0, #0xD20]                        @ Setup System Handlers 12-15 Priority Registers
                                                    @ Note: PnSV must be lowest priority, which is 0xFF
@
@    /* Return to caller.  */
@
    BX      lr


_tx_initialize_high_level

C函数

功能是ThreadX系统组件初始化
完成以后对_tx_thread_preempt_disable变量++,防止初始化完成前就开始调度而出问题
初始化完毕之前会调用tx_application_define完成需要的系统组件初始化
这个是用户自己编的 然后就去调度器了

任务调度

_tx_thread_schedule

汇编函数

@VOID   _tx_thread_schedule(VOID)
@{
    .global  _tx_thread_schedule
    .thumb_func
_tx_thread_schedule:
@
@    /* 这个函数只用于M7内核的首次调度请求。后续调度由PendSV处理函数处理 */
@
@    /* 清除掉优先级失能标志保证初始化结束以后M7可以重新调度 */
@
    MOV     r0, #0                                  @ Build value for TX_FALSE
    LDR     r2, =_tx_thread_preempt_disable         @ Build address of preempt disable flag
    /* 给_tx_thread_preempt_disable变量清0 */
    STR     r0, [r2, #0]                            @ Clear preempt disable flag
@
@    /* 清除掉FPCA位,因为浮点指令暂时不需要进栈 */
@
#ifdef TX_ENABLE_FPU_SUPPORT
    MRS     r0, CONTROL                             @ Pickup current CONTROL register
    BIC     r0, r0, #4                              @ Clear the FPCA bit
    MSR     CONTROL, r0                             @ Setup new CONTROL register
#endif
@
@    /* 开中断 */
@
    CPSIE   i
@
@    /* 第一次启动调度器,手动挂起PendSV中断  */
@
    MOV     r0, #0x10000000                         @ Load PENDSVSET bit
    MOV     r1, #0xE000E000                         @ Load NVIC base
    STR     r0, [r1, #0xD04]                        @ Set PENDSVBIT in ICSR
    DSB                                             @ 确定所有存储器操作已完成
    ISB                                             @ 清空流水线
@
@    /* 在这里一直等待PendSV中断触发  */
@
__tx_wait_here:
    B       __tx_wait_here                          @ Wait for the PendSV to happen
@}
__tx_ts_handler

汇编函数

__tx_ts_handler:

#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
@
@    /* 调用线程退出函数表示线程不再被执行【实际没有执行,宏定义没启动】  */
@
    CPSID   i                                       @ 关中断 Disable interrupts
    PUSH    {r0, lr}                                @ 保存LE Save LR (and r0 just for alignment)
    BL      _tx_execution_thread_exit               @ 调用线程退出函数 Call the thread exit function
    POP     {r0, lr}                                @ Recover LR
    CPSIE   i                                       @ Enable interrupts
#endif
/* _tx_thread_current_ptr目前值为0,_tx_thread_execute_ptr目前值为启动任务的TCB的地址*/
    LDR     r0, =_tx_thread_current_ptr             @ Build current thread pointer address
    LDR     r2, =_tx_thread_execute_ptr             @ Build execute thread pointer address
    MOV     r3, #0                                  @ Build NULL value
    /* _tx_thread_current_ptr目前值存到r1 */
    LDR     r1, [r0]                                @ Pickup current thread pointer
@
@    /* Determine if there is a current thread to finish preserving.  */
@   /* 为0则跳到__tx_ts_new */
    CBZ     r1, __tx_ts_new                         @ If NULL, skip preservation
@
@    /* 恢复PSP堆栈指针,保护当前线程 */
@
    STR     r3, [r0]                            @ 设置_tx_thread_current_ptr 为 NULL
    MRS     r12, PSP                            @ 读PSP堆栈指针(thread's stack pointer)
    STMDB   r12!, {r4-r11}                @ 保存剩余的寄存器值到当前的线程的堆栈里面
#ifdef TX_ENABLE_FPU_SUPPORT
    TST     LR, #0x10                               @ Determine if the VFP extended frame is present
    BNE     _skip_vfp_save
    VSTMDB  r12!,{s16-s31}                          @ Yes, save additional VFP registers
_skip_vfp_save:
#endif
    LDR     r4, =_tx_timer_time_slice               @ Build address of time-slice variable
    STMDB   r12!, {LR}                              @ 保存LR到栈
@
@    /* Determine if time-slice is active. If it isn't, skip time handling processing.  */
@
    LDR     r5, [r4]                                @ 取当前线程的时间片
    STR     r12, [r1, #8]                           @ Save the thread stack pointer
    CBZ     r5, __tx_ts_new                         @ If not active, skip processing
@
@    /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable.  */
@
    STR     r5, [r1, #24]                           @ Save current time-slice
@
@    /* Clear the global time-slice.  */
@
    STR     r3, [r4]                                @ Clear time-slice
@
@    /* Executing thread is now completely preserved!!!  */
@
__tx_ts_new:
@
@    /* 找新的线程开始执行 */
@
    CPSID   i                                       @ Disable interrupts
    LDR     r1, [r2]                                @ 把目前要执行的TCB地址赋值到r1
    CBZ     r1, __tx_ts_wait                        @ 如果地址为空,跳到__tx_ts_wait
@
@    /* Yes, another thread is ready for else, make the current thread the new thread.  */
@
    /*把要执行的线程TCB地址写到_tx_thread_current_ptr*/
    STR     r1, [r0]                                
    CPSIE   i                                       @ Enable interrupts
@
@    /* Increment the thread run count.  */
@
__tx_ts_restore:
    LDR     r7, [r1, #4]                            @ 取出线程的运行计数
    LDR     r4, =_tx_timer_time_slice               @ 取时间片变量的地址
    LDR     r5, [r1, #24]                           @ 取出当前线程的时间片计数值
    ADD     r7, r7, #1                              @ 运行计数+1
    STR     r7, [r1, #4]                            @ 写回去
@
@    /* Setup global time-slice with thread's current time-slice.  */
@
    STR     r5, [r4]                                @ 设置全局时间片变量

#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
@
@    /* 调用线程进入函数表明线程依据进入  */
@   /* 【实际没有执行,宏定义没启动】 */
    PUSH    {r0, r1}                                @ Save r0/r1
    BL      _tx_execution_thread_enter              @ Call the thread execution enter function
    POP     {r0, r1}                                @ Recover r3
#endif
@
@    /* Restore the thread context and PSP.  */
@
    LDR     r12, [r1, #8]                           @ 提取要运行的线程的栈顶指针
    LDMIA   r12!, {LR}                              @ 取出LR
#ifdef TX_ENABLE_FPU_SUPPORT
    /*测试LE与0x10相与后结果【看是不是有FPU相关指令吧】*/
    TST     LR, #0x10                               @ Determine if the VFP extended frame is present
    /*如果没有,则执行_skip_vfp_restore*/
    BNE     _skip_vfp_restore                       @ If not, skip VFP restore
    VLDMIA  r12!, {s16-s31}                         @ Yes, restore additional VFP registers
_skip_vfp_restore:
#endif
    LDMIA   r12!, {r4-r11}                          @ 恢复执行线程用到的寄存器
    MSR     PSP, r12                                @ 设置线程的堆栈指针
@
@    /* Return to thread.  */
@
    BX      lr                                      @ Return to thread!

_tx_thread_shell_entry

C函数

当进入或者退出一个线程时调用它

VOID  _tx_thread_shell_entry(VOID)
{

TX_INTERRUPT_SAVE_AREA

TX_THREAD       *thread_ptr;
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID            (*entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type);
#endif


    /* Pickup thread pointer.  */
    TX_THREAD_GET_CURRENT(thread_ptr)

    /* Perform any additional activities for tool or user purpose.  */
    TX_THREAD_STARTED_EXTENSION(thread_ptr)

#ifndef TX_DISABLE_NOTIFY_CALLBACKS

    /* Disable interrupts.  */
    TX_DISABLE

    /* 取出进入/退出线程的回调函数 */
    entry_exit_notify =  thread_ptr -> tx_thread_entry_exit_notify;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Determine if an application callback routine is specified.  */
    if (entry_exit_notify != TX_NULL)
    {

        /* Yes, notify application that this thread has been entered!  */
        (entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
    }
#endif

    /* 进入当前需要执行的线程.  */
    (thread_ptr -> tx_thread_entry) (thread_ptr -> tx_thread_entry_parameter);

    /* Suspend thread with a "completed" state.  */

    /* Determine if the application is using mutexes.  */
    if (_tx_thread_mutex_release != TX_NULL)
    {

        /* Yes, call the mutex release function via a function pointer that 
           is setup during mutex initialization.  */
        (_tx_thread_mutex_release)(thread_ptr);
    }

    /* Lockout interrupts while the thread state is setup.  */
    TX_DISABLE

#ifndef TX_DISABLE_NOTIFY_CALLBACKS

    /* Pickup the entry/exit application callback routine again.  */
    entry_exit_notify =  thread_ptr -> tx_thread_entry_exit_notify;
#endif

    /* Set the status to suspending, in order to indicate the suspension
       is in progress.  */
    thread_ptr -> tx_thread_state =  TX_COMPLETED;

    /* Thread state change.  */
    TX_THREAD_STATE_CHANGE(thread_ptr, TX_COMPLETED)

#ifdef TX_NOT_INTERRUPTABLE

#ifndef TX_DISABLE_NOTIFY_CALLBACKS

    /* Determine if an application callback routine is specified.  */
    if (entry_exit_notify != TX_NULL)
    {

        /* Yes, notify application that this thread has exited!  */
        (entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
    }
#endif

    /* Perform any additional activities for tool or user purpose.  */
    TX_THREAD_COMPLETED_EXTENSION(thread_ptr)

    /* Call actual non-interruptable thread suspension routine.  */
    _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));

    /* Restore interrupts.  */
    TX_RESTORE
#else

    /* Set the suspending flag. */
    thread_ptr -> tx_thread_suspending =  TX_TRUE;

    /* Setup for no timeout period.  */
    thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0);

    /* Temporarily disable preemption.  */
    _tx_thread_preempt_disable++;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Perform any additional activities for tool or user purpose.  */
    TX_THREAD_COMPLETED_EXTENSION(thread_ptr)

#ifndef TX_DISABLE_NOTIFY_CALLBACKS

    /* Determine if an application callback routine is specified.  */
    if (entry_exit_notify != TX_NULL)
    {

        /* Yes, notify application that this thread has exited!  */
        (entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
    }
#endif

    /* Call actual thread suspension routine.  */
    _tx_thread_system_suspend(thread_ptr);
#endif


#ifdef TX_SAFETY_CRITICAL

    /* If we ever get here, raise safety critical exception.  */
    TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}
汇编调度器tx_thread_schedule.S的执行逻辑分析图

在这里插入图片描述

线程管理

这一部分重点说说线程相关的前提知识和常用的API函数解读
解读的API函数:

  • 线程创建
  • 线程挂起
  • 线程恢复
  • 线程休眠
    其他的暂时不涉及了:)

ThreadX的文件结构为一个函数一个源文件的设计,给用户的API为宏,对应的功能函数经过多级的封装,最后才会到核心的功能代码。封装的目的主要是进行参数的合法性检查。

ThreadX比较独特的设计

  • 优先级阈值功能,优先级大于阈值的线程将不能抢占当前线程
  • 没有额外再定义链表的数据结构,而是直接使用组件的指针来实现“链表”的功能
  • 抢占禁止计数,这个类似于临界区保护【开关中断】计数的那种做法,该计数大于0则不能进行抢占操作,某些操作会引起该计数递增或递减。
  • “微内核”架构,系统调度内核和组件是区分开的,有别于支持MMU的SOC所能运行的微内核操作系统,对没有MMU的芯片来说,这个定义可能也并不是特别的明确,在无MMU的芯片上不能完全做到内核态与用户态的隔离。

线程栈帧

tx_thread_stack_build.S
该汇编函数描述了栈帧的结构和初始化的过程

@VOID   _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
@{
    .global  _tx_thread_stack_build
    .thumb_func
_tx_thread_stack_build:
@
@
@    /* Build a fake interrupt frame.  The form of the fake interrupt stack
@       on the Cortex-M7 should look like the following after it is built:
@
@       Stack Top:
@                       LR          Interrupted LR (LR at time of PENDSV)
@                       r4          Initial value for r4
@                       r5          Initial value for r5
@                       r6          Initial value for r6
@                       r7          Initial value for r7
@                       r8          Initial value for r8
@                       r9          Initial value for r9
@                       r10         Initial value for r10
@                       r11         Initial value for r11
@                       r0          Initial value for r0    (Hardware stack starts here!!)
@                       r1          Initial value for r1
@                       r2          Initial value for r2
@                       r3          Initial value for r3
@                       r12         Initial value for r12
@                       lr          Initial value for lr
@                       pc          Initial value for pc
@                       xPSR        Initial value for xPSR
@
@    Stack Bottom: (higher memory address)  */
@
    LDR     r2, [r0, #16]                           @ 取栈底的地址
    BIC     r2, r2, #0x7                            @ 对齐帧 r2=r2&0x07
    SUB     r2, r2, #68                             @ 减到帧底信息本身的大小6817*4】
    LDR     r3, =0xFFFFFFFD                         @ 构造初始的LR值【返回处理模式并使用PSP栈】
    STR     r3, [r2, #0]                            @ LR存到用户开辟的堆栈里
@
@    /* Actually build the stack frame.  */
@   /*一个个寄存器存个初始值到用户开辟的堆栈里*/
    MOV     r3, #0                                  @ Build initial register value
    STR     r3, [r2, #4]                            @ Store initial r4
    STR     r3, [r2, #8]                            @ Store initial r5
    STR     r3, [r2, #12]                           @ Store initial r6
    STR     r3, [r2, #16]                           @ Store initial r7
    STR     r3, [r2, #20]                           @ Store initial r8
    STR     r3, [r2, #24]                           @ Store initial r9
    STR     r3, [r2, #28]                           @ Store initial r10
    STR     r3, [r2, #32]                           @ Store initial r11
@
@    /* Hardware stack follows.  */
@
    STR     r3, [r2, #36]                           @ Store initial r0
    STR     r3, [r2, #40]                           @ Store initial r1
    STR     r3, [r2, #44]                           @ Store initial r2
    STR     r3, [r2, #48]                           @ Store initial r3
    STR     r3, [r2, #52]                           @ Store initial r12
    MOV     r3, #0xFFFFFFFF                         @ 一个非法的EXC_RETURN值
    STR     r3, [r2, #56]                           @ 存初始 lr
    STR     r1, [r2, #60]                           @ 存初始 pc
    MOV     r3, #0x01000000                         @ Only T-bit need be set
    STR     r3, [r2, #64]                           @ 存初始 xPSR
@
@    /* Setup stack pointer.  */
@    thread_ptr -> tx_thread_stack_ptr =  r2;
@
    STR     r2, [r0, #8]                            @ 存堆栈指针到TCB里面
                                                    @   control block
    BX      lr                                      @ Return to caller
@}
对应的栈帧结构图

栈帧结构图

返回系统状态

TX_THREAD_GET_SYSTEM_STATE()
返回当前系统的状态的宏,展开以后是

 (_tx_thread_system_state | __get_ipsr_value())

其中_tx_thread_system_state是当前系统的状态,__get_ipsr_value为一段汇编函数,作用是读取当前CPU的ipsr寄存器的值

__get_ipsr_value
__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void)
{

unsigned int  ipsr_value;

    __asm__ volatile (" MRS  %0,IPSR ": "=r" (ipsr_value) );
    return(ipsr_value);
}

ipsr寄存器表示正在处理的异常编号
将_tx_thread_system_state或上正在处理的异常编号,最后提供给系统组件做一些操作提供判断
_tx_thread_system_state表示当前系统状态,0为系统空闲或线程正在执行,其他值说明系统在初始化或者中断异常中

临界区保护(恢复)

__disable_interrupts & __restore_interrupts
__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void)
{

unsigned int  primask_value;

    __asm__ volatile (" MRS  %0,PRIMASK ": "=r" (primask_value) );
    __asm__ volatile (" CPSID i" : : : "memory" );
    return(primask_value);
}

__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value)
{

    __asm__ volatile (" MSR  PRIMASK,%0": : "r" (primask_value): "memory" );
}

会记录下关中断之后的primask值,恢复中断的时候需要把这个primask值重新赋值到对应的寄存器中
这样实现的好处就是开多少次就需要对应的关多少次

系统抢占功能检查

_tx_thread_system_preempt_check

检查当抢占失能标志禁止时【初始化或者中断或内部抢占禁止时】情况下,线程的抢占功能会不会导致线程调度的行为

VOID  _tx_thread_system_preempt_check(VOID)
{

ULONG           combined_flags;
TX_THREAD       *current_thread;
TX_THREAD       *thread_ptr;


    /* Combine the system state and preempt disable flags into one for comparison.  */
    TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)

    /* Determine if we are in a system state (ISR or Initialization) or internal preemption is disabled.  */
    if (combined_flags == ((ULONG) 0))
    {
    
        /* No, at thread execution level so continue checking for preemption.  */

        /* 取出当前线程的TCB.  */
        TX_THREAD_GET_CURRENT(current_thread)

        /* 取出即将执行的线程的TCB  */
        thread_ptr =  _tx_thread_execute_ptr;

        /* 检查优先级功能会不会出现  */
        if (current_thread != thread_ptr)
        {

#ifdef TX_ENABLE_STACK_CHECKING

            /* 检查堆栈  */
            TX_THREAD_STACK_CHECK(thread_ptr)
#endif
            /* 返回到用户层所以高优先级的线程可以被执行 */
            _tx_thread_system_return();
        }
    }
}

TX_THREAD_STACK_CHECK(thread_ptr)

系统抢占功能检查宏函数

    {
        //进临界区保护
        if (((thread_ptr)) && ((thread_ptr) -> tx_thread_id == TX_THREAD_ID))//线程合法性检查                                                   
        {
            
            if (((ULONG *) (thread_ptr) -> tx_thread_stack_ptr) < ((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr))     
            {
                 //线程的堆栈指针小于栈底指针       
                (thread_ptr) -> tx_thread_stack_highest_ptr =  (thread_ptr) -> tx_thread_stack_ptr;                             
            }                                                                                                                   
            if ((*((ULONG *) (thread_ptr) -> tx_thread_stack_start) != TX_STACK_FILL) ||                                        
                (*((ULONG *) (((UCHAR *) (thread_ptr) -> tx_thread_stack_end) + 1)) != TX_STACK_FILL) ||                        
                (((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr) < ((ULONG *) (thread_ptr) -> tx_thread_stack_start)))  
            {                                                                                                                   //堆栈合法性检查失败
                TX_RESTORE                                                                                                      
                _tx_thread_stack_error_handler((thread_ptr));                                                                   
                TX_DISABLE                                                                                                      
            }                                                                                                                   
            if (*(((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr) - 1) != TX_STACK_FILL)                                
            {                                                                                                                   //如果栈顶指针的前一个地址不是填写的默认值,那么就要进行堆栈分析
                TX_RESTORE                                                                                                      
                _tx_thread_stack_analyze((thread_ptr));                                                                         
                TX_DISABLE                                                                                                      
            }                                                                                                                   
        }                                                                                                                       
        //退出临界区                                                                                                              
    }

堆栈指针检查函数

_tx_thread_stack_analyze
VOID  _tx_thread_stack_analyze(TX_THREAD *thread_ptr)
{

TX_INTERRUPT_SAVE_AREA

ULONG       *stack_ptr;
ULONG       *stack_lowest;
ULONG       *stack_highest;
ULONG       size;


    /* Disable interrupts.  */
    TX_DISABLE

    /* 线程合法性检查  */
    if (thread_ptr != TX_NULL)
    {

        /* 线程合法性检查.  */
        if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
        {

            /* 取出当前堆栈指针  */
            stack_lowest =   TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start);
    
            /* Determine if the pointer is null.  */
            if (stack_lowest != TX_NULL)
            {

                /* 取出栈底指针.  */
                stack_highest =  TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr);

                /* Determine if the pointer is null.  */
                if (stack_highest != TX_NULL)
                {
    
                    /* Restore interrupts.  */
                    TX_RESTORE

                    /* We need to binary search the remaining stack for missing 0xEFEFEFEF 32-bit data pattern. 
                       This is a best effort algorithm to find the highest stack usage. */
                    do
                    {

                        /* 重新计算大小 取平均数算法吗?size = (最高-最低)/2*/
                        size =  (ULONG) (TX_ULONG_POINTER_DIF(stack_highest, stack_lowest))/((ULONG) 2);
                        //临时栈底指针值 = 最低+size
                        stack_ptr =  TX_ULONG_POINTER_ADD(stack_lowest, size);

                        /* 栈底指针检查.  */
                        if (*stack_ptr != TX_STACK_FILL)
                        {

                            /* 更新最高,继续在上半部分找 */
                            stack_highest =  stack_ptr;
                        }
                        else
                        {

                            /* 更新最高,继续在下半部分找 */
                            stack_lowest =  stack_ptr;
                        }

                    } while(size > ((ULONG) 1));//直到size等于0

                    /* Position to first used word - at this point we are within a few words.  */
                    while (*stack_ptr == TX_STACK_FILL)
                    {
                        //一直偏移直到偏移到的内存不再是FILL
                        /* Position to next word in stack.  */
                        stack_ptr =  TX_ULONG_POINTER_ADD(stack_ptr, 1);
                    }

                    /* Optional processing extension.  */
                    TX_THREAD_STACK_ANALYZE_EXTENSION

                    /* Disable interrupts.  */
                    TX_DISABLE

                    /* Check to see if the thread is still created.  */
                    if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
                    {

                        /* Yes, thread is still created.  */
        
                        /* 新的栈底指针合法性检查 */
                        if (stack_ptr > (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start)))
                        {
        
                            /* 新的栈底指针要小于之前的栈底指针  */
                            if (stack_ptr < (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr)))
                            {
            
                                /* 栈底指针不是已经用过的内存  */
                                if (*stack_ptr != TX_STACK_FILL)
                                {
        
                                    /* 设置新的栈顶指针  */
                                    thread_ptr -> tx_thread_stack_highest_ptr =  stack_ptr;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /* Restore interrupts.  */
    TX_RESTORE
}

线程控制块结构

typedef struct TX_THREAD_STRUCT
{
    ULONG               tx_thread_id;                   /* 线程控制块ID  */
    ULONG               tx_thread_run_count;            /* 线程运行次数计数     */
    VOID                *tx_thread_stack_ptr;           /* 线程堆栈指针   */
    VOID                *tx_thread_stack_start;         /* 用户堆栈开始地址   */
    VOID                *tx_thread_stack_end;           /* 用户堆栈结束地址     */
    ULONG               tx_thread_stack_size;           /* 用户堆栈大小               */
    ULONG               tx_thread_time_slice;           /* 当前时间片       */
    ULONG               tx_thread_new_time_slice;       /* 新时间片          */

    /* 下一个就绪线程,前一个就绪线程的指针*/
    struct TX_THREAD_STRUCT
                        *tx_thread_ready_next,
                        *tx_thread_ready_previous;

    /***************************************************************/

    TX_THREAD_EXTENSION_0
         
    CHAR                *tx_thread_name;                /* 线程名字     */
    UINT                tx_thread_priority;             /*线程优先级 (0-1023)  */
    UINT                tx_thread_state;                /* 线程目前的状态     */
    UINT                tx_thread_delayed_suspend;      /*延时挂起标志         */
    UINT                tx_thread_suspending;           /* 挂起标志       */
    UINT                tx_thread_preempt_threshold;    /* 优先级阈值         */
    
    /* 线程调度回调函数.
        Define the thread schedule hook. The usage of this is port/application specific, 
       but when used, the function pointer designated is called whenever the thread is
       scheduled and unscheduled.  
       */
    VOID                (*tx_thread_schedule_hook)(struct TX_THREAD_STRUCT *thread_ptr, ULONG id);

    /* 线程入口函数和传入参数  */
    VOID                (*tx_thread_entry)(ULONG id);
    ULONG               tx_thread_entry_parameter;

    /* 线程内部定时器块,用于线程休眠和超时请求*/
    TX_TIMER_INTERNAL   tx_thread_timer;

    /* 定义线程清理函数和相关数据结构,当一个线程的挂起操作被用户解除或超时 
    Define the thread's cleanup function and associated data.  This
       is used to cleanup various data structures when a thread 
       suspension is lifted or terminated either by the user or 
       a timeout.  */

    // 花旗控制块,后一个挂起的线程,前一个挂起的线程,挂起的选项和状态
    VOID                (*tx_thread_suspend_cleanup)(struct TX_THREAD_STRUCT *thread_ptr, ULONG suspension_sequence);
    VOID                *tx_thread_suspend_control_block;
    struct TX_THREAD_STRUCT
                        *tx_thread_suspended_next,
                        *tx_thread_suspended_previous;
    ULONG               tx_thread_suspend_info;
    VOID                *tx_thread_additional_suspend_info;
    UINT                tx_thread_suspend_option;
    UINT                tx_thread_suspend_status;

    /* Define the second port extension in the thread control block. This 
       is typically defined to whitespace or a pointer type in tx_port.h.  */
    TX_THREAD_EXTENSION_1

    /* 定义现在在已创建链表的后一个线程和前一个线程
    Define pointers to the next and previous threads in the 
       created list.  */
    struct TX_THREAD_STRUCT
                        *tx_thread_created_next,
                        *tx_thread_created_previous;

    /* Define the third port extension in the thread control block. This 
       is typically defined to whitespace in tx_port.h.  */
    TX_THREAD_EXTENSION_2

    /* 对接文件系统的接口 Define a pointer type for FileX extensions.  */
    VOID                *tx_thread_filex_ptr;

    /* 优先级继承变量,用在管理互斥信号量的优先级继承改变。 
    Define the priority inheritance variables. These will be used
       to manage priority inheritance changes applied to this thread 
       as a result of mutex get operations.  */
    UINT                tx_thread_user_priority;
    UINT                tx_thread_user_preempt_threshold;
    UINT                tx_thread_inherit_priority;
    
    /* 管理的互斥信号量的计数和对应互斥信号量链表头Define the owned mutex count and list head pointer.  */
    UINT                tx_thread_owned_mutex_count;
    struct TX_MUTEX_STRUCT
                        *tx_thread_owned_mutex_list;

    /* 定义最高的堆栈指针变量 Define the highest stack pointer variable.  */
    VOID                *tx_thread_stack_highest_ptr;   /* Stack highest usage pointer  */

    /* 定义线程进出时的应用回调函数
    Define the application callback routine used to notify the application when 
       the thread is entered or exits.  */
    VOID                (*tx_thread_entry_exit_notify)(struct TX_THREAD_STRUCT *thread_ptr, UINT type);

    /* Define the fourth port extension in the thread control block. This 
       is typically defined to whitespace in tx_port.h.  */
    TX_THREAD_EXTENSION_3

    /* 定义挂起序列号号。用来保证当清理函数执行的hi后保证挂起始终有效的变量
    Define suspension sequence number.  This is used to ensure suspension is still valid when 
       cleanup routine executes.  */
    ULONG               tx_thread_suspension_sequence;

    /* Define the user extension field.  This typically is defined 
       to white space, but some ports of ThreadX may need to have 
       additional fields in the thread control block.  This is 
       defined in the file tx_port.h.  */
    TX_THREAD_USER_EXTENSION

} TX_THREAD;

涉及到线程管理的重要变量

VOID * _tx_thread_system_stack_ptr

存放系统栈指针地址的指针。这个时用来存放系统栈起始位置【对应中断向量表的起始位置】,在_t
x_initialize_low_level中设置

TX_THREAD * _tx_thread_current_ptr

存放当前正在执行的线程,如果为空,则没有正在执行的线程

TX_THREAD * _tx_thread_execute_ptr

存放下一个要执行的线程,不一定要等于当前正在执行的线程

TX_THREAD * _tx_thread_created_ptr

已创建的线程链表指针

ULONG _tx_thread_created_count

已创建的线程计数

volatile UINT _tx_thread_preempt_disable

线程抢占失能变量。如果非0,说明抢占功能禁止。这个变量是ThreadX内部用来防护一个线程的优先级在另外一个线程恢复或者挂起中途时出问题的而定义的。

volatile ULONG _tx_thread_system_state

表示当前系统状态,0为系统空闲或线程正在执行,其他值说明系统在初始化或者中断异常中

ULONG _tx_thread_priority_maps[TX_MAX_PRIORITIES/32]

32位的优先级图。如果最大支持的优先级是32,那么就是1个字。其中的每一位表示对应优先级的一个或多个线程有任务就绪。

ULONG _tx_thread_preempted_maps[TX_MAX_PRIORITIES/32]

32位的抢占优先级图。其中的每一个1代表对应的抢占优先级下有启用的优先级阈值防止比当前优先级更高的相关线程抢占

UINT _tx_thread_highest_priority

就绪的最高优先级组,不一定和_tx_thread_execute_ptr的优先级一样

TX_THREAD * _tx_thread_priority_list[TX_MAX_PRIORITIES]

线程的优先级链表数组。每一个单元表示对应优先级下的就绪的首个线程TCB指针,如果对应的单元为NULL,则当前优先级下没有就绪的线程

VOID (*_tx_thread_mutex_release)(TX_THREAD *thread_ptr)

在线程完成或者终止的时候清除互斥信号量时的全局函数指针

线程创建

给用户调用的tx_thread_create只是一个宏
经过封装,tx_thread_create->_txe_thread_create->_tx_thread_create

简单的流程图
在这里插入图片描述

_tx_thread_create
UINT  _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input,
                            VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
                            ULONG time_slice, UINT auto_start)
{

TX_INTERRUPT_SAVE_AREA

TX_THREAD               *next_thread;
TX_THREAD               *previous_thread;
TX_THREAD               *saved_thread_ptr;
UINT                    saved_threshold =  ((UINT) 0);
UCHAR                   *temp_ptr;

#ifdef TX_ENABLE_STACK_CHECKING
ULONG                   new_stack_start;
ULONG                   updated_stack_start;
#endif

#ifndef TX_DISABLE_STACK_FILLING

    /* 首先设置堆栈的内存区域为一个已知的值,后面可以用来做堆栈检查用  */
    TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size);
#endif

#ifdef TX_ENABLE_STACK_CHECKING

    /* 栈顶和栈底头尾设置的EF值用来实时做堆栈检查  */
    stack_size =  ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));

    /* 确保堆栈是对齐的  */
    new_stack_start =  TX_POINTER_TO_ULONG_CONVERT(stack_start);
    updated_stack_start =  ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));

    /* 确保新的栈顶和更新的栈顶是不一样的  */
    if (new_stack_start != updated_stack_start)
    {
    
        /* 如果是的话,偏移4字节,避免交叠*/
        stack_size =  stack_size - (sizeof(ULONG));
    }

    /* 更新栈顶指针  */
    stack_start =  TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
#endif

    /* Prepare the thread control block prior to placing it on the created
       list.  */

    /* 初始化线程TCB  */
    TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD)));

    /* Place the supplied parameters into the thread's control block.  */
    thread_ptr -> tx_thread_name =              name_ptr;
    thread_ptr -> tx_thread_entry =             entry_function;
    thread_ptr -> tx_thread_entry_parameter =   entry_input;
    thread_ptr -> tx_thread_stack_start =       stack_start;
    thread_ptr -> tx_thread_stack_size =        stack_size;
    thread_ptr -> tx_thread_priority =          priority;
    thread_ptr -> tx_thread_user_priority =     priority;
    thread_ptr -> tx_thread_time_slice =        time_slice;
    thread_ptr -> tx_thread_new_time_slice =    time_slice;
    thread_ptr -> tx_thread_inherit_priority =  ((UINT) TX_MAX_PRIORITIES);

    /* Calculate the end of the thread's stack area.  */
    temp_ptr =  TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
    temp_ptr =  (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
    thread_ptr -> tx_thread_stack_end =         TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);

    /* Preemption-threshold is enabled, setup accordingly.  */
    thread_ptr -> tx_thread_preempt_threshold =       preempt_threshold;
    thread_ptr -> tx_thread_user_preempt_threshold =  preempt_threshold;

    /* Now fill in the values that are required for thread initialization.  */
    thread_ptr -> tx_thread_state =  TX_SUSPENDED;

    /* Setup the necessary fields in the thread timer block.  */
    TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)

    /* Perform any additional thread setup activities for tool or user purpose.  */
    TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)

    /* 线程堆栈初始化,主要是设计到具体硬件的上下文切换的部分的初始化  */
    _tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);

#ifdef TX_ENABLE_STACK_CHECKING

    /* 设置堆栈最大能使用的指针  */
    thread_ptr -> tx_thread_stack_highest_ptr =  thread_ptr -> tx_thread_stack_ptr;
#endif

    /* Prepare to make this thread a member of the created thread list.  */
    TX_DISABLE

    /* Load the thread ID field in the thread control block.  */
    thread_ptr -> tx_thread_id =  TX_THREAD_ID;

    /* 把线程指针添加到已创建的线程链表里  */
    if (_tx_thread_created_count == TX_EMPTY)
    {

        /* 已创建线程链表为空   */
        _tx_thread_created_ptr =                    thread_ptr;
        thread_ptr -> tx_thread_created_next =      thread_ptr;
        thread_ptr -> tx_thread_created_previous =  thread_ptr;
    }
    else
    {

        /* 已创建线程链表非空,加到末尾 */
        next_thread =  _tx_thread_created_ptr;
        previous_thread =  next_thread -> tx_thread_created_previous;

        /* Place the new thread in the list.  */
        next_thread -> tx_thread_created_previous =  thread_ptr;
        previous_thread -> tx_thread_created_next =  thread_ptr;

        /* Setup this thread's created links.  */
        thread_ptr -> tx_thread_created_previous =  previous_thread;
        thread_ptr -> tx_thread_created_next =      next_thread;
    }
    
    /* 增加已创建的线程数目  */
    _tx_thread_created_count++;

    /* If trace is enabled, register this object.  */
    TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)

    /* If trace is enabled, insert this event into the trace buffer.  */
    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_CREATE, thread_ptr, priority, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size, TX_TRACE_THREAD_EVENTS)

    /* Register thread in the thread array structure.  */
    TX_EL_THREAD_REGISTER(thread_ptr)

    /* Log this kernel call.  */
    TX_EL_THREAD_CREATE_INSERT

#ifndef TX_NOT_INTERRUPTABLE

    /* 临时禁止抢占  */
    _tx_thread_preempt_disable++;
#endif

    /* 判断是不是开了立即就绪,开了调用线程恢复函数,之后判断抢占条件 */
    if (auto_start == TX_AUTO_START)
    {

        /* 判断线程创建是不是调用自初始化阶段*/
        if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
        {

            /* Yes, this create call was made from initialization.  */

            /*取出当前需要执行线程指针,也就是目前最高优先级需要执行的线程。不需要中断锁,因为中断在初始化阶段是被关闭的。*/
            saved_thread_ptr =  _tx_thread_execute_ptr;

            /* 判断有没有要执行的线程  */
            if (saved_thread_ptr != TX_NULL)
            {
                
                /* 如果有,初始化完毕以后立即执行  */

                /* 存在当前线程的线程优先级阈值.  */
                saved_threshold =  saved_thread_ptr -> tx_thread_preempt_threshold;

                /* 对于初始化阶段,临时的设置优先级阈值为目前的设置的优先级,确保高优先级线程可以在初始化完成以后运行一次*/
                saved_thread_ptr -> tx_thread_preempt_threshold =  saved_thread_ptr -> tx_thread_priority;
            }
        }
        else
        {

            /* Simply set the saved thread pointer to NULL.  */
            saved_thread_ptr =  TX_NULL;
        }

        /* Restore previous interrupt posture.  */
        TX_RESTORE

        /* Perform any additional activities for tool or user purpose.  */
        TX_THREAD_CREATE_EXTENSION(thread_ptr)

        /* 调用线程恢复函数恢复就绪的线程执行  */
        _tx_thread_system_resume(thread_ptr);
        
        /* 判断是不是线程的优先级阈值需要被恢复 */
        if (saved_thread_ptr != TX_NULL)
        {

            /* 恢复之前修改的线程优先级阈值,这仅限于初始化阶段 */
            saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
        }
    }
    else
    {

        /* Restore interrupts.  */
        TX_RESTORE

        /* Perform any additional activities for tool or user purpose.  */
        TX_THREAD_CREATE_EXTENSION(thread_ptr)

        /* Disable interrupts.  */
        TX_DISABLE

        /* 重新启动抢占  */
        _tx_thread_preempt_disable--;

        /* Restore interrupts.  */
        TX_RESTORE

        /* 抢占检查  */
        _tx_thread_system_preempt_check();
    }

    /* Always return a success.  */
    return(TX_SUCCESS);
}

线程恢复

给用户调用的是一个宏tx_thread_resume经过封装
_txe_thread_resume->_tx_thread_resume->_tx_thread_system_resume

_tx_thread_resume
UINT  _tx_thread_resume(TX_THREAD *thread_ptr)
{

	TX_INTERRUPT_SAVE_AREA

	UINT        status;
	TX_THREAD   *saved_thread_ptr;
	UINT        saved_threshold =  ((UINT) 0);
  /* Lockout interrupts while the thread is being resumed.  */
    TX_DISABLE

    /* If trace is enabled, insert this event into the trace buffer.  */
    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)

    /* Log this kernel call.  */
    TX_EL_THREAD_RESUME_INSERT

    /* 判断是不是处于挂起状态 */
    if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
    {

        /* 判断是不是在初始化阶段调用的 */
        if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
        {

            /* Yes, this resume call was made from initialization.  */

            /* 取出当前执行的线程指针存下来,对应目前最高优先级需要执行的线程。线程锁是不需要的
			,因此在初始化阶段是不需要开中断的*/
            saved_thread_ptr =  _tx_thread_execute_ptr;

            /* 判断现在是不是有线程要执行 */
            if (saved_thread_ptr != TX_NULL)
            {
                
                /* 是的话,初始化完的时候就有线程要恢复执行了 */

                /* 存当前线程的线程优先值阈值 */
                saved_threshold =  saved_thread_ptr -> tx_thread_preempt_threshold;

                /* 对于初始化阶段,临时设置优先级阈值为当前线程的优先级,保证最高优先级的线程在初始化完的时候会运行一次 */
                saved_thread_ptr -> tx_thread_preempt_threshold =  saved_thread_ptr -> tx_thread_priority;
            }
        }
        else
        {

            /* saved_thread_ptr为NULL  */
            saved_thread_ptr =  TX_NULL;
        }
		/* 临时禁止抢占*/
        _tx_thread_preempt_disable++;

        /* Restore interrupts.  */
        TX_RESTORE

        /* 调用真正的线程恢复函数 */
        _tx_thread_system_resume(thread_ptr);
		/* 判断有没有线程需要恢复呢 
		Determine if the thread's preemption-threshold needs to be restored.  */
        if (saved_thread_ptr != TX_NULL)
        {

            /* 恢复最高优先级的线程优先级阈值。只在初始化的时候有 */
            saved_thread_ptr -> tx_thread_preempt_threshold =  saved_threshold;
        }
		/* Return successful completion.  */
        return(TX_SUCCESS);
	}
    else if (thread_ptr -> tx_thread_delayed_suspend == TX_TRUE)
    {

        /* 如果有延时挂起,清除延时挂起标志*/
        thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;

        /* Setup delayed suspend lifted return status.  */
        status =  TX_SUSPEND_LIFTED;
    }
    else
    {

        /* Setup invalid resume return status.  */
        status =  TX_RESUME_ERROR;
    }

    /* Restore interrupts.  */
    TX_RESTORE
	/* Return completion status. */
    return(status);
}
_tx_thread_system_resume
VOID  _tx_thread_system_resume(TX_THREAD *thread_ptr)
{

	UINT            priority;
	ULONG           priority_bit;
	TX_THREAD       *head_ptr;
	TX_THREAD       *tail_ptr;
	TX_THREAD       *execute_ptr;
	TX_THREAD       *current_thread;
	ULONG           combined_flags;

    /* Check this thread's stack.  */
    TX_THREAD_STACK_CHECK(thread_ptr)

    /* Lockout interrupts while the thread is being resumed.  */
    TX_DISABLE
    /* 如果需要的话关掉超时定时器 */
    if (thread_ptr -> tx_thread_timer.tx_timer_internal_list_head != TX_NULL)
    {

        /* 关掉线程的超时定时器  */
        _tx_timer_system_deactivate(&(thread_ptr -> tx_thread_timer));
    }
    else
    {

        /* 清掉剩余的时间确保不会启动 */
        thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0);
    }

    /* 抢占失能计数--   */
    _tx_thread_preempt_disable--;

    /* 确保线程没有处于正在挂起状态。如果正在挂起的话就已经在挂起链表里了,啥也不需要做了*/
    if (thread_ptr -> tx_thread_suspending == TX_FALSE)
    {

        /* 线程没有正在挂起。现在确保线程没有处在就绪状态 */
        if (thread_ptr -> tx_thread_state != TX_READY)
        {

            /* 判断延时挂起标志有吗? */
            if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE)
            {
				//没有。则恢复这个线程
                /* Resume the thread!  */
                
                /* Make this thread ready.  */

                /* Change the state to ready.  */
                thread_ptr -> tx_thread_state =  TX_READY;

                /* Pickup priority of thread.  */
                priority =  thread_ptr -> tx_thread_priority;

                /* Thread state change.  */
                TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)

                /* Log the thread status change.  */
                TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)

                /* 判断处于该优先级的其他线程有没有就绪的 */
                head_ptr =  _tx_thread_priority_list[priority];
                if (head_ptr == TX_NULL)
                {
					//没有的话
                    /* 把当前线程加到就绪链表的头部 
					First thread at this priority ready.  Add to the front of the list.  */
                    _tx_thread_priority_list[priority] =       thread_ptr;
                    thread_ptr -> tx_thread_ready_next =       thread_ptr;
                    thread_ptr -> tx_thread_ready_previous =   thread_ptr;

                    /* Or in the thread's priority bit. 标记对应的优先级下有线程就绪了  */
                    TX_MOD32_BIT_SET(priority, priority_bit)
                    _tx_thread_priority_maps[MAP_INDEX] =  _tx_thread_priority_maps[MAP_INDEX] | priority_bit;

                    /* 判断这个新就绪的线程是不是比目前的最高优先级高 
					Determine if this newly ready thread is the highest priority.  */
                    if (priority < _tx_thread_highest_priority)
                    {

                        /* A new highest priority thread is present. */
						//是最高优先级,更新最高优先级
                        /* Update the highest priority variable.  */
                        _tx_thread_highest_priority =  priority;

                        /* 取出下一个要执行的线程
						Pickup the execute pointer. Since it is going to be referenced multiple
                           times, it is placed in a local variable.  */
                        execute_ptr =  _tx_thread_execute_ptr;
                        
                        /* 如果下一个要执行的线程为空 
						Determine if no thread is currently executing.  */
                        if (execute_ptr == TX_NULL)
                        {

                            /* 下一个就是你
							Simply setup the execute pointer.  */
                            _tx_thread_execute_ptr =  thread_ptr;
                        }
                        else
                        {
                        
                            /* Another thread has been scheduled for execution.  */
							//另一个线程需要被调度执行
                            /* 判断这个线程有更高的优先级,判断抢占是否允许Check to see if this is a higher priority thread and determine if preemption is allowed.  */
                            if (priority < execute_ptr -> tx_thread_preempt_threshold)
                            {
								//该线程的优先级比下一个执行的优先级阈值高【优先级小为高】
                                /* Determine if the preempted thread had preemption-threshold set.  */
								//判断下一个执行的线程的优先级阈值不等于线程本身的优先级
                                if (execute_ptr -> tx_thread_preempt_threshold != execute_ptr -> tx_thread_priority)
                                {
                                    /* 这个线程会被高于自身优先级阈值的线程抢占 
									Remember that this thread was preempted by a thread above the thread's threshold.  */
                                    TX_MOD32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
                                    _tx_thread_preempted_maps[MAP_INDEX] =  _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
                                }
                                /* 修改下一个需要执行的线程*/
                                _tx_thread_execute_ptr =  thread_ptr;
                            }
                        }
                    }
                }
                else
                {

                    /*该优先级下有另外一个线程就绪 No, there are other threads at this priority already ready.  */

                    /* 加这一个线程到就绪链表 Just add this thread to the priority list.  */
                    tail_ptr =                                 head_ptr -> tx_thread_ready_previous;
                    tail_ptr -> tx_thread_ready_next =         thread_ptr;
                    head_ptr -> tx_thread_ready_previous =     thread_ptr;
                    thread_ptr -> tx_thread_ready_previous =   tail_ptr;
                    thread_ptr -> tx_thread_ready_next =       head_ptr;
                }
            }

            /* Else, delayed suspend flag was set.  */
            else
            {

                /*清掉延时挂起标志,改变状态  */
                thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;
                thread_ptr -> tx_thread_state =            TX_SUSPENDED;
            }
        }
    }
    else
    {
    
        /* 这个恢复操作发送在前一个线程挂起的中途 
		A resumption occurred in the middle of a previous thread suspension.  */
        
        /* 确保线程的状态不是完成也不是终止
		Make sure the type of suspension under way is not a terminate or
           thread completion.  In either of these cases, do not void the 
           interrupted suspension processing.  */
        if (thread_ptr -> tx_thread_state != TX_COMPLETED)
        {
            
            /* Make sure the thread isn't terminated.  */
            if (thread_ptr -> tx_thread_state != TX_TERMINATED)
            {

                /* 检查延时挂起标志没有设置 No, now check to see if the delayed suspension flag is set.  */
                if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE)
                {
	
                    /* 没有 Clear the suspending flag.  */
                    thread_ptr -> tx_thread_suspending =   TX_FALSE;

                    /* 恢复运行Restore the state to ready.  */
                    thread_ptr -> tx_thread_state =        TX_READY;

                    /* Thread state change.  */
                    TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)

                    /* Log the thread status change.  */
                    TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
                }
                else
                {
                
                    /* 有的话,清除延时挂起标志 Clear the delayed suspend flag and change the state.  */
                    thread_ptr -> tx_thread_delayed_suspend =  TX_FALSE;
                    thread_ptr -> tx_thread_state =            TX_SUSPENDED;
                }
            }
        }
    }

    /* Pickup thread pointer.  */
    TX_THREAD_GET_CURRENT(current_thread)

    /* Restore interrupts.  */
    TX_RESTORE

    /*判断抢占条件  Determine if a preemption condition is present.  */
    if (current_thread != _tx_thread_execute_ptr)
    {
        /* 取出接下来要执行的线程 Pickup the next execute pointer.  */
        thread_ptr =  _tx_thread_execute_ptr;

        /* Check this thread's stack.  */
        TX_THREAD_STACK_CHECK(thread_ptr)
        /* Now determine if preemption should take place. This is only possible if the current thread pointer is
           not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
        TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
        if (combined_flags == ((ULONG) 0))
        {
            /* 判断是不是要回到系统内部呢,回到系统内部 Preemption is needed - return to the system!  */
            _tx_thread_system_return();
        }
    }
}

线程挂起

ThreadX给用户提供调用的是一个宏函数tx_thread_suspend

经过_txe_thread_suspend->_tx_thread_suspend->_tx_thread_system_suspend
真正的挂起函数是 _tx_thread_system_suspend

_tx_thread_suspend
UINT _tx_thread_suspend(TX_THREAD *thread_ptr)
{

    TX_INTERRUPT_SAVE_AREA

    TX_THREAD *current_thread;
    UINT status;

    /* Lockout interrupts while the thread is being suspended.  */
    TX_DISABLE

    /* 取出当前运行的线程  */
    TX_THREAD_GET_CURRENT(current_thread)

    /* If trace is enabled, insert this event into the trace buffer.  */
    TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr->tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)

    /* Log this kernel call.  */
    TX_EL_THREAD_SUSPEND_INSERT

    /* 判断是不是就绪  */
    if (thread_ptr->tx_thread_state == TX_READY)
    {

        /* Initialize status to success.  */
        status = TX_SUCCESS;

        /* 判断是不是处于线程上下文  */
        if (TX_THREAD_GET_SYSTEM_STATE() == 0)
        {

            /* Yes, we are in a thread context.  */

            /* 判断当前运行的线程是不是要挂起的线程 */
            if (current_thread == thread_ptr)
            {

                /* 判断抢占禁止标志是不是非0【禁止抢占】 */
                if (_tx_thread_preempt_disable != ((UINT)0))
                {

                    /*当前运行线程不能被挂起,因为抢占被禁止*/
                    status = TX_SUSPEND_ERROR;
                }
            }
        }

        /* 判断状态OK吗 */
        if (status == TX_SUCCESS)
        {

            /* 设置状态为挂起 */
            thread_ptr->tx_thread_state = TX_SUSPENDED;
            /* 设置状态为挂起标志 */
            thread_ptr->tx_thread_suspending = TX_TRUE;

            /* 设置没有超时周期  */
            thread_ptr->tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG)0);

            /* 临时禁止抢占  */
            _tx_thread_preempt_disable++;

            /* Restore interrupts.  */
            TX_RESTORE

            /* 调用真正的挂起函数  */
            _tx_thread_system_suspend(thread_ptr);
            /* If MISRA is not enabled, return directly.  */
            return (TX_SUCCESS);
        }
    }
    /* 以下为线程处于其他状态时的处理 */
    else if (thread_ptr->tx_thread_state == TX_TERMINATED)
    {

        /* Thread is terminated.  */
        status = TX_SUSPEND_ERROR;
    }
    else if (thread_ptr->tx_thread_state == TX_COMPLETED)
    {

        /* Thread is completed.  */
        status = TX_SUSPEND_ERROR;
    }
    else if (thread_ptr->tx_thread_state == TX_SUSPENDED)
    {

        /* Already suspended, just set status to success.  */
        status = TX_SUCCESS;
    }
    else
    {

        /* Just set the delayed suspension flag.  */
        thread_ptr->tx_thread_delayed_suspend = TX_TRUE;

        /* Set status to success.  */
        status = TX_SUCCESS;
    }

    /* Restore interrupts.  */
    TX_RESTORE

    /* Always return success, since this function does not perform error 
       checking.  */
    return (status);
}
_tx_thread_system_suspend
VOID _tx_thread_system_suspend(TX_THREAD *thread_ptr)
{
    TX_INTERRUPT_SAVE_AREA

    UINT priority;
    UINT base_priority;
    ULONG priority_map;
    ULONG priority_bit;
    ULONG combined_flags;
    TX_THREAD *ready_next;
    TX_THREAD *ready_previous;
    TX_THREAD *current_thread;
    ULONG timeout;

    /* 取出当前运行的线程  */
    TX_THREAD_GET_CURRENT(current_thread)

    /* Lockout interrupts while the thread is being suspended.  */
    TX_DISABLE
    /* 需要挂起的线程是当前运行的线程 */
    if (thread_ptr == current_thread)
    {

        /* 取出目前剩余的等待时间  */
        timeout = thread_ptr->tx_thread_timer.tx_timer_internal_remaining_ticks;

        /* 剩余等待时间不为0   */
        if (timeout != TX_NO_WAIT)
        {

            /* 等于等待时间不是极大值   */
            if (timeout != TX_WAIT_FOREVER)
            {

                /* 以当前的定时器剩余值激活被挂起线程的定时器 */
                _tx_timer_system_activate(&(thread_ptr->tx_thread_timer));
            }
        }

        /* 是的话,重置当前运行的线程的时间片  */
        _tx_timer_time_slice = thread_ptr->tx_thread_new_time_slice;
    }
    /* 抢占禁止标志-- */
    _tx_thread_preempt_disable--;
    /* 判断正在挂起标志置位。如果没有则说明其已经恢复运行了*/
    if (thread_ptr->tx_thread_suspending == TX_TRUE)
    {

        /* Thread state change.  */
        TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr->tx_thread_state)

        /* Log the thread status change.  */
        TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr->tx_thread_state)
        /* Log the thread status change.  */
        TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND, thread_ptr, thread_ptr->tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&priority), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
        /* 实际挂起需要挂起的线程,但是首先先清除正在挂起标志 */
        thread_ptr->tx_thread_suspending = TX_FALSE;

        /* 取出它的优先级  */
        priority = thread_ptr->tx_thread_priority;

        /* 取出下一个就绪的线程*/
        ready_next = thread_ptr->tx_thread_ready_next;

        /* 判断下一个优先的线程和当前需要挂起的线程的关系 */
        if (ready_next != thread_ptr)
        {

            /* 不等,说明本优先级下有其他线程就绪 */

            /* 取出需要挂起的线程的前一个就绪线程*/
            ready_previous = thread_ptr->tx_thread_ready_previous;

            /* 将这个线程移除优先级链表 */
            ready_next->tx_thread_ready_previous = ready_previous;
            ready_previous->tx_thread_ready_next = ready_next;

            /* 判断这个线程是不是该优先级下的第一个就绪线程 */
            if (_tx_thread_priority_list[priority] == thread_ptr)
            {

                /* 更新链表为下一个就绪的线程  */
                _tx_thread_priority_list[priority] = ready_next;
                /* 检查线程优先级阈值有无启用的 Check for a thread preempted that had preemption threshold set.  */
                if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG)0))
                {

                    /* 要把该线程对应的优先级阈值使能清除掉  */
                    TX_MOD32_BIT_SET(priority, priority_bit)
                    _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
                }
            }
        }
        else
        {
            //目前没有其他线程就绪,就需要将链表头设置为NULL,和前面的操作类似
            _tx_thread_priority_list[priority] = TX_NULL;
            /* Clear this priority bit in the ready priority bit map.  */
            TX_MOD32_BIT_SET(priority, priority_bit)
            _tx_thread_priority_maps[MAP_INDEX] = _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
            /* Check for a thread preempted that had preemption-threshold set.  */
            if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG)0))
            {

                /* Ensure that this thread's priority is clear in the preempt map.  */
                TX_MOD32_BIT_SET(priority, priority_bit)
                _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
            }
            /* Setup the base priority to zero.  */
            base_priority = ((UINT)0);
            /* Setup working variable for the priority map.  */
            priority_map = _tx_thread_priority_maps[MAP_INDEX];

            /* 检查下还有没有其他线程就绪要执行 */
            if (priority_map == ((ULONG)0))
            {

                /* 设置最高优先级和下一个要执行的线程*/
                _tx_thread_highest_priority = ((UINT)TX_MAX_PRIORITIES);
                _tx_thread_execute_ptr = TX_NULL;
                /* Restore interrupts.  */
                TX_RESTORE
                /* 检查抢占禁止计数,这仅仅会出现在当前的线程指针与下一个要执行的线程指针不同且系统状态和抢占禁止都为空时*/
                TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
                if (combined_flags == ((ULONG)0))
                {
                    /* 如果需要抢占,返回到系统内核 */
                    _tx_thread_system_return();
                }
                /* Return to caller.  */
                return;
            }
            else
            {

                /* 其他优先级的线程就绪要运行 */

                /* 计算优先级图的最低位【这里用了CLZ和RBIT指令】 */
                TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)

                /* 设置最高优先级变量  Setup the next highest priority variable.  */
                _tx_thread_highest_priority = base_priority + ((UINT)priority_bit);
            }
        }
        /* 判断要挂起的线程是不是接下来要运行的线程 */
        if (thread_ptr == _tx_thread_execute_ptr)
        {

            /* 选择最高优先级的线程运行  */
            _tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
            /*判断是否有优先级阈值生效 Determine if a previous thread with preemption-threshold was preempted.  */
            if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG)0))
            {

                /* 会有线程抢占发生Yes, there was a thread preempted when it was using preemption-threshold.  */

                /* 抢占禁止计数++ Disable preemption.  */
                _tx_thread_preempt_disable++;

                /* Restore interrupts.  */
                TX_RESTORE

                /* 为了中断锁的时间一致性,这里打开一下中断 Interrupts are enabled briefly here to keep the interrupt
                   lockout time deterministic.  */

                /* Disable interrupts again.  */
                TX_DISABLE

                /* 抢占禁止计数-- Decrement the preemption disable variable.  */
                _tx_thread_preempt_disable--;

                /* 计算启动了优先级阈值的线程被高于阈值的线程打断 Calculate the thread with preemption threshold set that
                   was interrupted by a thread above the preemption level.  */
                /* Setup the base priority to zero.  */
                base_priority = ((UINT)0);

                /* 读取临时的优先级阈值图 Setup temporary preempted map.  */
                priority_map = _tx_thread_preempted_maps[MAP_INDEX];

                /* 计算优先级图的最低位 Calculate the lowest bit set in the priority map. */
                TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)

                /* 计算最高的抢占优先级 Setup the highest priority preempted thread.  */
                priority = base_priority + ((UINT)priority_bit);

                /* 判断目前最高优先级是否比最高优先级线程的优先级阈值高 Determine if the next highest priority thread is above the highest priority threshold value.  */
                if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority]->tx_thread_preempt_threshold))
                {

                    /* 线程不允许执行,直到阈值内的线程完成或者时自己比阈值低 Thread not allowed to execute until earlier preempted thread finishes or lowers its 
                       preemption-threshold.  */
                    _tx_thread_execute_ptr = _tx_thread_priority_list[priority];

                    /* 清除其在优先级阈值的对应位,因为抢占恢复了 Clear the corresponding bit in the preempted map, since the preemption has been restored.  */
                    TX_MOD32_BIT_SET(priority, priority_bit)
                    _tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
                }
            }
            /* Restore interrupts.  */
            TX_RESTORE

            /* 判断抢占是否应该发生。检查抢占禁止计数,这仅仅会出现在当前的线程指针与下一个要执行的线程指针不同且系统状态和抢占禁止都为空时*/
            /* Determine if preemption should take place. This is only possible if the current thread pointer is
               not the same as the execute thread pointer AND the system state and preempt disable flags are clear.  */
            TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
            if (combined_flags == ((ULONG)0))
            {
                /* Preemption is needed - return to the system!  */
                _tx_thread_system_return();
            }
            /* Return to caller.  */
            return;
        }
    }
    /* Restore interrupts.  */
    TX_RESTORE

    /* 检查是否出现抢占条件 */
    if (current_thread != _tx_thread_execute_ptr)
    {
        /* 取出下一个运行的线程指针 */
        thread_ptr = _tx_thread_execute_ptr;

        /* Check this thread's stack.  */
        TX_THREAD_STACK_CHECK(thread_ptr)
        /*判断抢占是否应该发生。检查抢占禁止计数,这仅仅会出现在当前的线程指针与下一个要执行的线程指针不同且系统状态和抢占禁止都为空时*/
        TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
        if (combined_flags == ((ULONG)0))
        {
            /* 需要抢占,返回系统内核  */
            _tx_thread_system_return();
        }
    }

    /* Return to caller.  */
    return;
}

线程休眠

这个用的比较多,所以来看看它的实现,具体功能就是让指定的线程休眠指定的毫秒数,然后恢复执行

和前面类似提供给用户的接口是一个宏tx_thread_sleep,封装为_tx_thread_sleep。内部会调用_tx_thread_system_suspend。

_tx_thread_sleep
UINT  _tx_thread_sleep(ULONG timer_ticks)
{

    TX_INTERRUPT_SAVE_AREA

    UINT            status;
    TX_THREAD       *thread_ptr;

    /* 关中断 */
    TX_DISABLE

    /* 取出当前在运行的线程  */
    TX_THREAD_GET_CURRENT(thread_ptr)

    /* Determine if this is a legal request.  */

    /* 是否为空  */
    if (thread_ptr == TX_NULL)
    {

        /* Restore interrupts.  */
        TX_RESTORE
        
        /* Illegal caller of this service.  */
        status =  TX_CALLER_ERROR;
    }
    
    /*是不是从初始化和中断中调用  */
    else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
    {

        /* Restore interrupts.  */
        TX_RESTORE
        
        /*禁止从初始化和中断中调用  */
        status =  TX_CALLER_ERROR;
    }
    /* 是不是系统定时器调用的  */
    else if (thread_ptr == &_tx_timer_thread)
    {

        /* Restore interrupts.  */
        TX_RESTORE
        
        /* Illegal caller of this service.  */
        status =  TX_CALLER_ERROR;
    }


    /* 判断休眠时间是不是0  */
    else if (timer_ticks == ((ULONG) 0))
    {

        /* Restore interrupts.  */
        TX_RESTORE
      
        /* Just return with a successful status.  */
        status =  TX_SUCCESS;
    }
    else
    {

        /* 判断抢占禁止计数器是不是0  */
        if (_tx_thread_preempt_disable != ((UINT) 0))
        {

            /* Restore interrupts.  */
            TX_RESTORE
            /*抢占禁止计数器不为0时,禁止挂起任务*/
            /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion.  */
            status =  TX_CALLER_ERROR;
        }
        else
        {
        
            /* If trace is enabled, insert this event into the trace buffer.  */
            TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SLEEP, TX_ULONG_TO_POINTER_CONVERT(timer_ticks), thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)

            /* Log this kernel call.  */
            TX_EL_THREAD_SLEEP_INSERT

            /* Suspend the current thread.  */

            /* 将线程的状态置为休眠  */
            thread_ptr -> tx_thread_state =    TX_SLEEP;

            /*设置挂起标志位1 */
            thread_ptr -> tx_thread_suspending =  TX_TRUE;

            /* 挂起状态为成功  */
            thread_ptr -> tx_thread_suspend_status =  TX_SUCCESS;

            /* 设置内部定时器的剩余时间为指定时间  */
            thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  timer_ticks;

            /* 抢占禁止计数++ Temporarily disable preemption.  */
            _tx_thread_preempt_disable++;

            /* Restore interrupts.  */
            TX_RESTORE

            /* 调用系统的线程挂起函数 */
            _tx_thread_system_suspend(thread_ptr);

            /* Return status to the caller.  */
            status =  thread_ptr -> tx_thread_suspend_status;
        }
    }
    
    /* Return completion status.  */
    return(status);
}
### 回答1: USART_Mode_Tx代表USART(通用同步异步收发器)的传输模式,其中Tx代表Transmit,意为发送模式。 在USART中,Tx模式允许数据从USART的数据寄存器发送到外部设备或另一USART。这种模式通常用于向其他设备发送数据或通信。 需要注意的是,USART可以同时支持Tx和Rx(接收)模式,因此可以实现双向通信。 ### 回答2: USART_Mode_Tx是在使用USART通信协议时的传输模式之一。USART是通用同步/异步收发传输器的缩写,它是一种常用的串行通信接口。 USART_Mode_Tx表示选中了串口的发送模式。在这种模式下,我们可以向外部设备发送数据。USART通信包含一个发送线路和一个接收线路。USART_Mode_Tx将串口的发送线路选中,以便我们可以将要发送的数据发送给外部设备。 使用USART_Mode_Tx模式时,我们需要将待发送的数据写入USART数据寄存器,然后串口会将数据发送给外设。在发送过程中,我们需要配置一些参数,如波特率、数据位数、停止位等,以确保数据的正确传输。 USART通信通常用于与外部设备进行数据交互,如与传感器、无线模块或其他外设的通信。通过配置正确的USART_Mode_Tx模式,我们可以将需要传送的数据发送出去,实现与外设的数据通信。 总之,USART_Mode_Tx是USART通信协议中的一种传输模式,用于将数据从主设备发送到外部设备,通过正确配置参数,可以实现与外设的数据交互。 ### 回答3: USART_Mode_Tx是一个使用USART通信的模式,它是指USART的发送模式。 USART是Universal Synchronous/Asynchronous Receiver/Transmitter(通用同步/异步接收/发送器)的缩写,是一种用于串行通信的硬件设备。USART_Mode_Tx即为它的发送模式,表示USART在此模式下只负责发送数据。 在USART_Mode_Tx模式下,我们可以通过USART发送数据。它可以以同步或异步的方式传输数据。同步方式是在通信的发送和接收端之间使用一个共享的时钟信号进行同步。异步方式则是通过使用启始位、数据位、校验位和停止位来完成数据的传输。 使用USART_Mode_Tx模式,我们首先需要配置USART的相关参数,例如波特率、数据位数、停止位数和校验位等。然后,我们可以调用特定的函数将需要发送的数据写入USART的数据寄存器,USART会自动将数据发送出去。 USART_Mode_Tx模式在很多应用方面非常常见,例如将数据发送到另一个设备、与其他设备进行通信等。它具有高速、稳定和可靠的特点,可以在不同的通信环境下使用。 总之,USART_Mode_Tx是USART通信的一种模式,表示USART在此模式下只负责发送数据。通过配置相关参数和调用相应的函数,我们可以使用USART_Mode_Tx模式将数据发送出去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值