Pandora IOT Development Board Learning (HAL Library) – Experiment 4 Serielles Kommunikationsexperiment (Studienhinweise)

Der Code dieses Artikels bezieht sich auf die pünktliche atomare Routine

Experimentelle Funktionen

In der pünktlichen atomaren Routine wird das globale Array USART_RX_BUF[USART_REC_LEN]verwendet, um die von der seriellen Schnittstelle empfangenen Daten zu speichern, und zwei Bits werden als Flag-Bits (Empfangsbeendigungs-Flag) verwendet.

u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA = 0;     //接收状态标记

Quellcode der Routine: (main.c)

Dieses Experiment realisiert das Empfangen und Senden des seriellen Ports.Ob der Empfang abgeschlossen ist, wird in der Interrupt-Service-Funktion des seriellenPorts beurteilt (siehe die USART1_IRQHandler()Funktion ).

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "beep.h"
#include "key.h"

/*********************************************************************************
			  ___   _     _____  _____  _   _  _____  _____  _   __
			 / _ \ | |   |_   _||  ___|| \ | ||_   _||  ___|| | / /
			/ /_\ \| |     | |  | |__  |  \| |  | |  | |__  | |/ /
			|  _  || |     | |  |  __| | . ` |  | |  |  __| |    \
			| | | || |_____| |_ | |___ | |\  |  | |  | |___ | |\  \
			\_| |_/\_____/\___/ \____/ \_| \_/  \_/  \____/ \_| \_/

 *	******************************************************************************
 *	正点原子 Pandora STM32L475 IoT开发板	实验4
 *	串口通讯实验	HAL库版本
 *	技术支持:www.openedv.com
 *	淘宝店铺:http://openedv.taobao.com
 *	关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 *	广州市星翼电子科技有限公司
 *	作者:正点原子 @ALIENTEK
 *	******************************************************************************/

int main(void)
{
    
    
    u8 len;
    u16 times = 0;

    HAL_Init();
    SystemClock_Config();	//初始化系统时钟为80M
    delay_init(80); 		//初始化延时函数    80M系统时钟
    uart_init(115200);		//初始化串口,波特率为115200

    LED_Init();				//初始化LED
    KEY_Init();				//初始化KEY

    while(1)
    {
    
    
        if(USART_RX_STA & 0x8000)
        {
    
    
            len = USART_RX_STA & 0x3fff; //得到此次接收到的数据长度
            printf("\r\n您发送的消息为:\r\n");
            HAL_UART_Transmit(&UART1_Handler, (uint8_t*)USART_RX_BUF, len, 1000);	//发送接收到的数据

            while(__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_TC) != SET);		//等待发送结束

            printf("\r\n\r\n");//插入换行
            USART_RX_STA = 0;
        }
        else
        {
    
    
            times++;

            if(times % 5000 == 0)
            {
    
    
                printf("\r\nALIENTEK 潘多拉 STM32L475 IOT开发板 串口实验\r\n");
                printf("正点原子@ALIENTEK\r\n\r\n\r\n");
            }

            if(times % 200 == 0)printf("请输入数据,以回车键结束\r\n");
            if(times % 30 == 0)LED_B_TogglePin; //闪烁LED,提示系统正在运行.

            delay_ms(10);
        }
    }
}

Code-Analyse

HAL_Init()

HAL_Init()Die Definition lautet wie folgt: (siehe Anmerkungen zu den implementierten Funktionen)

HAL_StatusTypeDef HAL_Init(void)
{
    
    
  HAL_StatusTypeDef  status = HAL_OK;

  /* 配置 Flash 预取,指令缓存,数据缓存        */
  /* 默认配置为:预存取关闭 指令缓存和数据缓存开启 */     
#if (INSTRUCTION_CACHE_ENABLE == 0)  // Flash开启预存取配置,能加速CPU代码的执行
   __HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
#endif /* INSTRUCTION_CACHE_ENABLE */

#if (DATA_CACHE_ENABLE == 0)
   __HAL_FLASH_DATA_CACHE_DISABLE();
#endif /* DATA_CACHE_ENABLE */ 

#if (PREFETCH_ENABLE != 0)
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); // 配置 NVIC 优先级分组

  /* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */
  if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK) //初始化滴答定时器,时钟节拍设置为 1ms
  {
    
    
    status = HAL_ERROR;
  }
  else
  {
    
    
    /* Init the low level hardware */
    HAL_MspInit(); // 低速的外设初始化,比如 GPIO、中断等的设置(使用 STM32CubeMx 生成代码时会将低速外设初始
                   // 代码当这类函数里,其他情况下可以忽略这个函数
  }

  /* Return function status */
  return status;
}

HAL_InitTick()
Tick-Timer-Clock-Tick-Initialisierungsfunktion

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    
    
  HAL_StatusTypeDef  status = HAL_OK;

  /*Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock/1000UL) != 0U) // 系统时钟/1000,中断周期为 1ms
  {
    
    
    status = HAL_ERROR;
  }
  else
  {
    
    
    /*Configure the SysTick IRQ priority */
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0); // 将滴答定时器的中断优先级设置为最高
  }

  /* Return function status */
  return status;
}

SystemClock_Config()

SystemClock_Config()Die Funktionsdefinition lautet wie folgt: (Für die spezifische Implementierung der Funktion siehe die Kommentare, nur als Referenz)

void SystemClock_Config(void)
{
    
    
    HAL_StatusTypeDef	ret = HAL_OK;

    RCC_OscInitTypeDef RCC_OscInitStruct; // 定义振荡器初始化结构体变量
    RCC_ClkInitTypeDef RCC_ClkInitStruct; // 定义时钟初始化结构体变量

    __HAL_RCC_PWR_CLK_ENABLE(); // 使能电源控制时钟

    /*Initializes the CPU, AHB and APB busses clocks*/
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 将 HSE(外部高速时钟)作为时钟源
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;  // 开启 HSE
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 开启 PLL(锁相环)
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // 将 HSE 作为 PLL 的时钟源
    RCC_OscInitStruct.PLL.PLLM = 1; // PLL-VCO 输入时钟分频系数,1 表示 2 分频(8 / 2 = 4M,本开发板外部晶振频率为 8MHz)
    RCC_OscInitStruct.PLL.PLLN = 20; // PLL-VCO 输出时钟倍频系数,4 * 20 = 80M,即输出时钟频率为 80MHz
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // SAI 时钟的分频系数
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // SDMMC1, RNG 和 USB 的时钟分频系数
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // 主系统时钟的分频系数

    ret = HAL_RCC_OscConfig(&RCC_OscInitStruct); //初始化时钟配置

    if(ret != HAL_OK)	while(1);

    /*Initializes the CPU, AHB and APB busses clocks*/
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; // 将所有时钟同时进行配置
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 将 PLL 作为系统时钟源
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB 不分频
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1 不分频
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 不分频


    ret	= HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4); // 配置时钟初始结构体变量,
    //使用 Flash 延迟4,等待状态(延迟)的数量需要根据CPU时钟(HCLK)的频率和内部电压范围来选择,具体怎么
    //选需要参考芯片手册

    if(ret != HAL_OK)	while(1);

    /*Configure the main internal regulator output voltage*/
    ret = HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); //内部寄存器输出电压配置
    // 下面是 HAL_PWREx_ControlVoltageScaling() 函数说明的部分内容:
    //PWR_REGULATOR_VOLTAGE_SCALE1 Regulator voltage output range 1 mode, typical output voltage
    // at 1.2 V, system frequency up to 80 MHz.

    if(ret != HAL_OK)	while(1);
}

delay_init()

Der Tick-Timer wurde HAL_Init()in initialisiert, und die folgende Funktion fac_usweist tatsächlich einen Wert zu (derzeit ohne Beteiligung des Betriebssystems, und andere Codes werden vorerst nicht untersucht).

static u32 fac_us = 0;							//us延时倍乘数
/**
 * @brief	初始化延迟函数,SYSTICK的时钟固定为AHB时钟
 *
 * @param   SYSCLK	系统时钟频率
 *
 * @return  void
 */
void delay_init(u8 SYSCLK)
{
    
    
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
    u32 reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
    fac_us = SYSCLK;						//不论是否使用OS,fac_us都需要使用

#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
    reload = SYSCLK;					  //每秒钟的计数次数 单位为K
    reload *= 1000000 / delay_ostickspersec;	//根据delay_ostickspersec设定溢出时间
    //reload为24位寄存器,最大值:16777216,在80M下,约209.7ms左右
    fac_ms = 1000 / delay_ostickspersec;		//代表OS可以延时的最少单位
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
    SysTick->LOAD = reload; 					//每1/OS_TICKS_PER_SEC秒中断一次
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
#endif
}

usart_Init()

Die Initialisierungsfunktion des seriellen Ports, die zugehörige GPIO-Initialisierung ist nicht in dieser Funktion (aber tatsächlich wird die GPIO-Konfiguration auch in dieser Funktion durchgeführt).

/**
 * @brief	初始化串口1函数
 *
 * @param	bound	串口波特率
 *
 * @return  void
 */
void uart_init(u32 bound)
{
    
    
    //UART 初始化设置
    UART1_Handler.Instance = USART1;					  //USART1
    UART1_Handler.Init.BaudRate = bound;				  //波特率
    UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式
    UART1_Handler.Init.StopBits = UART_STOPBITS_1;	  //一个停止位
    UART1_Handler.Init.Parity = UART_PARITY_NONE;		  //无奇偶校验位
    UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
    UART1_Handler.Init.Mode = UART_MODE_TX_RX;		  //收发模式
    HAL_UART_Init(&UART1_Handler);					    //HAL_UART_Init()会使能UART1

    __HAL_UART_ENABLE_IT(&UART1_Handler, UART_IT_RXNE); //开启接收中断
    HAL_NVIC_EnableIRQ(USART1_IRQn);					//使能USART1中断通道
    HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);				//抢占优先级3,子优先级3
}


In der obigen HAL_UART_Init()Funktion ruft HAL_UART_MspInit()HAL_UART_MspInit() diese Funktion auf, um die Pins und Interrupt-Funktionen der seriellen Schnittstelle zu konfigurieren. Die Definition dieser Funktion in der Routine ist wie folgt:


/**
 * @brief	HAL库串口底层初始化,时钟使能,引脚配置,中断配置
 *
 * @param	huart	串口句柄
 *
 * @return  void
 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_Initure;

    if(huart->Instance == USART1) //如果是串口1,进行串口1 MSP初始化
    {
    
    
        __HAL_RCC_GPIOA_CLK_ENABLE();				//使能GPIOA时钟
        __HAL_RCC_USART1_CLK_ENABLE();				//使能USART1时钟

        GPIO_Initure.Pin = GPIO_PIN_9;				//PA9
        GPIO_Initure.Mode = GPIO_MODE_AF_PP;		//复用推挽输出
        GPIO_Initure.Pull = GPIO_PULLUP;			//上拉
        GPIO_Initure.Speed = GPIO_SPEED_FAST;		//高速
        GPIO_Initure.Alternate = GPIO_AF7_USART1;	//复用为USART1
        HAL_GPIO_Init(GPIOA, &GPIO_Initure);	   	//初始化PA9

        GPIO_Initure.Pin = GPIO_PIN_10;				//PA10
        HAL_GPIO_Init(GPIOA, &GPIO_Initure);	   	//初始化PA10
    }
}

LED_Init()

Die den Pins der LEDs entsprechenden GPIOs werden in der LED-Initialisierungsfunktion konfiguriert.

/**
 * @brief	LED IO初始化函数
 *
 * @param   void
 *
 * @return  void
 */
void LED_Init(void)
{
    
    
	/*
		LED-B	PE9
		LED-G	PE8
		LED-R	PE7	
	*/
    GPIO_InitTypeDef GPIO_InitStruct;  // 定义一个GPIO初始化结构体变量

    __HAL_RCC_GPIOE_CLK_ENABLE();  // 使能GPIOE的时钟

    GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9; // 同时配置 3 个引脚
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
    GPIO_InitStruct.Pull = GPIO_PULLUP;  // 默认上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  // 速度设为高速(25 MHz to 50 MHz)
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);  // 初始化结构体变量

	// 将 3 个引脚同时置高
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9, GPIO_PIN_SET);
}

delay_ms()

delay_ms()Was hier läuft, ist delay_us(), dass die Verzögerung delay_us()durch einen Tick-Timer realisiert wird. Das obige delay_init()hat fac_us auf 80 gesetzt, und es dauert 10-6 Sekunden, bis der Tick-Timer 80 Mal gezählt hat (die Systemuhr ist 80 MHz), was 1 us entspricht.

/**
 * @brief	延时毫秒(ms)函数
 *
 * @param   nms		需要延时多少毫秒
 *
 * @return  void
 */
void delay_ms(u16 nms)
{
    
    
    u32 i;

    for(i = 0; i < nms; i++) delay_us(1000);
}

/**
 * @brief	延时微秒(us)函数
 *
 * @remark	nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
 *
 * @param   nus		需要延时多少微秒
 *
 * @return  void
 */
void delay_us(u32 nus)
{
    
    
    u32 ticks;
    u32 told, tnow, tcnt = 0;
    u32 reload = SysTick->LOAD;				//LOAD的值
    ticks = nus * fac_us; 					//需要的节拍数
    told = SysTick->VAL;        			//刚进入时的计数器值

    while(1)
    {
    
    
        tnow = SysTick->VAL;

        if(tnow != told)
        {
    
    
            if(tnow < told)tcnt += told - tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
            else tcnt += reload - tnow + told;
			
            told = tnow;
            if(tcnt >= ticks)break;			//时间超过/等于要延迟的时间,则退出.
        }
    }
}

HAL_UART_Transmit()

Sendefunktion der seriellen Schnittstelle, der Funktionsprototyp ist wie folgt:

/**
  * @brief Send an amount of data in blocking mode.
  * @note When FIFO mode is enabled, writing a data in the TDR register adds one
  *       data to the TXFIFO. Write operations to the TDR register are performed
  *       when TXFNF flag is set. From hardware perspective, TXFNF flag and
  *       TXE are mapped on the same bit-field.
  * @param huart   UART handle.  串口句柄
  * @param pData   Pointer to data buffer. 要发送的数据
  * @param Size    Amount of data to be sent. 要发送的数据大小
  * @param Timeout Timeout duration.  超时时间
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Lese- und Schreibstatus der seriellen Schnittstelle

Hauptfunktion

while(__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_TC) != SET);		//等待发送结束

Es wird verwendet, um den Abschlussstatus der Übertragung über die serielle Schnittstelle zu erhalten.Ähnliche Statusbits sind:

#define UART_FLAG_TXE      USART_ISR_TXE           /*!< 串口发送数据空  */
#define UART_FLAG_TC       USART_ISR_TC            /*!< 串口发送数据完成   */
#define UART_FLAG_RXNE     USART_ISR_RXNE_RXFNE    /*!< 串口读取数据寄存器非空 */
#define UART_FLAG_RXFNE    USART_ISR_RXNE_RXFNE    /*!< 串口接收缓存非空  */
#define UART_FLAG_RXNE     USART_ISR_RXNE          /*!< 串口读数据非空  */
#define UART_FLAG_IDLE     USART_ISR_IDLE          /*!< 串口空闲标志  */
#define UART_FLAG_ORE      USART_ISR_ORE           /*!< UART overrun error                        */
#define UART_FLAG_NE       USART_ISR_NE            /*!< UART noise error                          */
#define UART_FLAG_FE       USART_ISR_FE            /*!< UART frame error                          */
#define UART_FLAG_PE       USART_ISR_PE            /*!< UART parity error                         */

printf() umleiten

Fügen Sie dem Projekt den folgenden Code hinzu, mit dem Sie Daten an die serielle Schnittstelle printf()drucken können.

#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
    
    
    int handle;
};

FILE __stdout;
/**
 * @brief	定义_sys_exit()以避免使用半主机模式
 *
 * @param	void
 *
 * @return  void
 */
void _sys_exit(int x)
{
    
    
    x = x;
}
/**
 * @brief	重定义fputc函数
 *
 * @param	ch		输出字符量
 * @param	f		文件指针
 *
 * @return  void
 */
int fputc(int ch, FILE *f)
{
    
    
    while((USART1->ISR & 0X40) == 0); //循环发送,直到发送完毕

    USART1->TDR = (u8) ch;
    return ch;
}
#endif

LED-Betriebsfunktion

Die Steuerfunktion der LED ist eine Makrofunktion, HAL_GPIO_WritePin()die HAL_GPIO_TogglePin()jeweils zwei Bibliotheksfunktionen verwendet.

#define LED_B(n)			(n?HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_RESET))
#define LED_B_TogglePin     HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_9)

USART1_IRQHandler()

Der Kommentar der Routine deklariert, dass dieses Experiment nicht die Verarbeitungslogik der HAL-Bibliothek (unter Verwendung der Callback-Funktion) verwendet, sondern die Methode der direkten Definition der Interrupt-Service-Funktion verwendet. Die Codelogik ist nicht kompliziert, und in der Routine wurden ausführliche Kommentare gegeben.

u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA = 0;     //接收状态标记
/**
 * @brief	串口1中断服务程序
 *
 * @remark	下面代码我们直接把中断控制逻辑写在中断服务函数内部
 * 			说明:采用HAL库处理逻辑,效率不高。
 *
 * @param   void
 *
 * @return  void
 */
void USART1_IRQHandler(void)
{
    
    
    u8 Res;

    if((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_RXNE) != RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        HAL_UART_Receive(&UART1_Handler, &Res, 1, 1000);

        if((USART_RX_STA & 0x8000) == 0) //接收未完成
        {
    
    
            if(USART_RX_STA & 0x4000) //接收到了0x0d
            {
    
    
                if(Res != 0x0a)USART_RX_STA = 0; //接收错误,重新开始

                else USART_RX_STA |= 0x8000;	//接收完成了
            }
            else //还没收到0X0D
            {
    
    
                if(Res == 0x0d)USART_RX_STA |= 0x4000;
                else
                {
    
    
                    USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res ;
                    USART_RX_STA++;

                    if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收
                }
            }
        }
    }
    HAL_UART_IRQHandler(&UART1_Handler);
}

HAL_UART_Receive()

Empfangsfunktion der seriellen Schnittstelle, der Funktionsprototyp ist wie folgt:


/**
  * @brief Receive an amount of data in blocking mode.
  * @note When FIFO mode is enabled, the RXFNE flag is set as long as the RXFIFO
  *       is not empty. Read operations from the RDR register are performed when
  *       RXFNE flag is set. From hardware perspective, RXFNE flag and
  *       RXNE are mapped on the same bit-field.
  * @param huart   UART handle. 串口句柄
  * @param pData   Pointer to data buffer. 接收的数据缓存
  * @param Size    Amount of data to be received. 要接收的数据大小
  * @param Timeout Timeout duration. 超时时间
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

HAL_UART_IRQHandler()

Die Funktion wird in USART1_IRQHandler()der letzten Zeile von aufgerufen, und hier HAL_UART_IRQHandler()ist, wie andere im Internet diese Funktion erklären:

Rufen Sie die Interrupt-Behandlung öffentlicher Funktionen der HAL-Bibliothek auf. Funktion: Beurteilen und Verarbeiten der empfangenen Daten, Beurteilen, ob es sich um eine Sendeunterbrechung oder eine Empfangsunterbrechung handelt, und dann Senden und Empfangen von Daten, die in der Unterbrechungsdienstfunktion verwendet werden.

Bildbeschreibung hier einfügen

——https://www.csdn.net/tags/MtjaYgxsMzE5MTYtYmxvZwO0O0OO0O0O.html

Ich denke du magst

Origin blog.csdn.net/weixin_43772810/article/details/125299366
Empfohlen
Rangfolge