精华内容
下载资源
问答
  • CA1N1、CAN2总线接收,中断接收。 平台:STM32F405RGT6、标准库。 CAN1配置 void CAN1_Mode_Init(u8 mode) { GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure; CAN_...

    CAN1总线发送,中断接收。
    平台:STM32F405RGT6、标准库。

    CAN1配置

    void CAN1_Mode_Init(u8 mode)
    {
      	GPIO_InitTypeDef GPIO_InitStructure; 
    	CAN_InitTypeDef        CAN_InitStructure;
      	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
       	NVIC_InitTypeDef  NVIC_InitStructure;
    
        //使能相关时钟
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 
      	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	
    	
        //初始化GPIO
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
    	
    	//引脚复用映射配置
    	GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
    	GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为CAN1
    	  
      	//CAN单元设置
       	CAN_InitStructure.CAN_TTCM=DISABLE;	//非时间触发通信模式   
      	CAN_InitStructure.CAN_ABOM=DISABLE;	//软件自动离线管理	  
      	CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
      	CAN_InitStructure.CAN_NART=ENABLE;	//禁止报文自动传送 
      	CAN_InitStructure.CAN_RFLM=DISABLE;	//报文不锁定,新的覆盖旧的  
      	CAN_InitStructure.CAN_TXFP=DISABLE;	//优先级由报文标识符决?
    	 
    /***************************************************************************************/		
        //配置can工作模式	
      	CAN_InitStructure.CAN_Mode= mode;	 //模式设置 
    		//CAN初始化
    		//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
    		//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
    		//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
    		//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
    		//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
    		//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
    		//Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);
    		//则波特率为:42M/((6+7+1)*6)=500Kbps
    		//返回值:0,初始化OK;
    		//    其他,初始化失败; 
    		/* // 100K
      	CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=CAN_BS1_7tq; //时间段1的时间单元.  Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=CAN_BS2_6tq; //时间段2的时间单元.  Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=6;  //分频系数(Fdiv)为brp+1	
    		*/
    		
    		/* // 50K
      	CAN_InitStructure.CAN_SJW=CAN_SJW_3tq;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=CAN_BS1_6tq; //时间段1的时间单元.  Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=CAN_BS2_1tq; //时间段2的时间单元.  Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=84;  //分频系数(Fdiv)为brp+1	
    		*/
    		
    		 // 25K
      	CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=CAN_BS1_6tq; //时间段1的时间单元.  Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=CAN_BS2_1tq; //时间段2的时间单元.  Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=210;  //分频系数(Fdiv)为brp+1	
    				
    		
    		 /*// 20K
      	CAN_InitStructure.CAN_SJW=CAN_SJW_3tq;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=CAN_BS1_6tq; //时间段1的时间单元.  Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=CAN_BS2_1tq; //时间段2的时间单元.  Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=210;  //分频系数(Fdiv)为brp+1	
    		*/
    		
    		/* // 10K
      	CAN_InitStructure.CAN_SJW=CAN_SJW_3tq;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
      	CAN_InitStructure.CAN_BS1=CAN_BS1_6tq; //时间段1的时间单元.  Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
      	CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2的时间单元.  Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
      	CAN_InitStructure.CAN_Prescaler=420;  //分频系数(Fdiv)为brp+1	
    		*/
    		
    /***************************************************************************************/			
      	CAN_Init(CAN1, &CAN_InitStructure);   // 初始化CAN1 
        
    		//配置过滤器
     	CAN_FilterInitStructure.CAN_FilterNumber=0;	  //过滤器0
      	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
      	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位 
      	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
      	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
      	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
      	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
       	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
      	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
      	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
    		
    	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.		    
      
      	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      	NVIC_Init(&NVIC_InitStructure);
    }   
    
    

    CAN1发送函数

    u8 CAN1_Send_Msg(u8* msg,u8 len)
    {	
      u8 mbox;
      u16 i=0;
      CanTxMsg TxMessage;
      TxMessage.StdId=0x12;	 // 标准标识符为0
      TxMessage.ExtId=0x12;	 // 设置扩展标示符(29位)
      TxMessage.IDE=0;		   // 使用扩展标识符
      TxMessage.RTR=0;		   // 消息类型为数据帧,一帧8位
      TxMessage.DLC=len;	   // 发送两帧信息
      for(i=0;i<len;i++)
      TxMessage.Data[i]=msg[i];				 // 第一帧信息          
      mbox= CAN_Transmit(CAN1, &TxMessage);   
      i=0;
      while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
      if(i>=0XFFF)return 1;
      return 0;		
    }
    

    CAN1中断服务函数

    void CAN1_RX0_IRQHandler(void)
    {
    	CanRxMsg RxMessage;
    	//CAN_Receive(CAN1, 0, &RxMessage);
    	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据	
    	led_cnt=0;
    	falshCnt=0;
    	ledSpeed=FLASH_FAST;
    }
    

    代码运行现象:数据3秒发一次,CAN1中断函数收到数据之后LED快闪3次,然后又恢复到1秒1闪。
    下面是工程文件,里面还包括CAN2的中断接收函数。
    STM32F4 CAN1 CAN2数据收发 中断接收

    展开全文
  • HAL库实现将接收逻辑全写在中断服务函数里面而不重定义回调函数,并且不会不进中断

    之前一直用的固件库跑c8t6和zet6,现在有幸接触到stm32H743用到HAL库,学习嘛都是踩坑,csdn,然后...理解底层库的代码

    本人有幸遇到了H7的串口中断接收只进去一次的Bug,于是马上csdn,才发现网上全是在回调函数里写接收处理的逻辑,而我不一样,可能我比你们帅我就要把接收逻辑写在中断服务函数里面(狗头),其实是因为最先接触的板子是103的c8t6所有例程都是在服务函数里处理的,所有养成了习惯,做H7的工程时就直接移植了;但找了2天我也没在网上没有找到将逻辑写在服务函数里面的,于是乎,花费一天时间看HAL库的串口驱动程序,终于!调通了,话不多说,

    上!代!码!

    串口初始化和固件库的配置逻辑大体一样:

     
    void UART2_Config(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;

        RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
                
        UART2_RX_GPIO_CLK_ENABLE();
        UART2_TX_GPIO_CLK_ENABLE();
        
        /* 配置串口2时钟源*/
        RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
        RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
        HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
        /* 使能 UART2 时钟 */
        UART2_CLK_ENABLE();

        /**USART2 GPIO Configuration    
        PA2     ------> USART2_TX
        PA3    ------> USART2_RX 
        */
        /* 配置Tx引脚为复用功能  */
        GPIO_InitStruct.Pin = UART2_TX_PIN;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = UART2_TX_AF;
        HAL_GPIO_Init(UART2_TX_GPIO_PORT, &GPIO_InitStruct);
        
        /* 配置Rx引脚为复用功能 */
        GPIO_InitStruct.Pin = UART2_RX_PIN;
        GPIO_InitStruct.Alternate = UART2_RX_AF;
        HAL_GPIO_Init(UART2_RX_GPIO_PORT, &GPIO_InitStruct); 
        
        /* 配置串USART2 模式 */
        Uart2_Handle.Instance = UART2;
        Uart2_Handle.Init.BaudRate = 115200;
        Uart2_Handle.Init.WordLength = UART_WORDLENGTH_8B;
        Uart2_Handle.Init.StopBits = UART_STOPBITS_1;
        Uart2_Handle.Init.Parity = UART_PARITY_NONE;
        Uart2_Handle.Init.Mode = UART_MODE_TX_RX;

        HAL_UART_Init(&Uart2_Handle);

        /*串口2中断初始化 */
        HAL_NVIC_SetPriority(UART2_IRQ, 0, 3);
        HAL_NVIC_EnableIRQ(UART2_IRQ);
        /*配置串口接收中断 */
        __HAL_UART_ENABLE_IT(&Uart2_Handle,UART_IT_RXNE); 
    }

    /**
      * @brief  UART2 GPIO 配置,工作模式配置。115200 8-N-1
      */  

    需要注意调用 __HAL_UART_ENABLE_IT(&Uart2_Handle,UART_IT_RXNE)函数使能中断。

    接下来是中断服务函数的编写:


    unsigned char SHU1[42]={0};  //接收缓存
    unsigned char ces[1];
    unsigned char MODE=0; 
    u8toointt pos1,pos2,pos3,pos4,pos5,pos6;    
    float posBi[7]={0,0,0,0,0,0,0};//机械臂角度

    void UART2_IRQHandler(void)
    {
        static unsigned char conunt=0; // 接收记录
        static unsigned char i = 0;     //记录数据个数
        static unsigned char j = 0; 
        uint32_t timeout=0;
        uint32_t maxDelay=0x1FFFF;

        //调用HAL_UART_Receive_IT函数进行接收可再次开启中断
        HAL_UART_IRQHandler(&Uart2_Handle);    //调用HAL库中断处理公用函数
        timeout=0;
        while (HAL_UART_GetState(&Uart2_Handle)!=HAL_UART_STATE_READY)//等待就绪
        {
            timeout++;超时处理
            if(timeout>maxDelay) break;        
        }
         
        timeout=0;
        while(HAL_UART_Receive_IT(&Uart2_Handle,(uint8_t *)ces, 1)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
        {
            timeout++; //超时处理
            if(timeout>maxDelay) break;    
        }
    //处理接收到的一个字节
            switch(conunt)
            {
                case 0:
                    if(ces[0] == 0xFF) conunt++;
                    else conunt=0;    
                    break;
                case 1:
                    if(ces[0] == 0xFF) conunt ++; //数据帧头        
                    else conunt = 0;
                    break;
                case 2://角度包
                    SHU1[i] = ces[0];
                    i++;
                    if(i==6)//接收完成了开始验证
                    {
                        if(SHU1[5]==0xFE)//判断数据帧尾 
                        {
                            switch(SHU1[0])
                            {
                                case 0x01:
                        for(j=0;j<=3;j++) //pos1角度接收 
                                    {
                                        pos1.Receive_Val[j]=SHU1[j+1];
                                    }
                                   posBi[1]=pos1.Act_val;   
                                break;
                                case 0x02:
                        for(j=0;j<=3;j++) //pos2角度接收 
                                    {
                                        pos2.Receive_Val[j]=SHU1[j+1];
                                    }
                                  posBi[2]=pos2.Act_val;   
                                break;     
                                case 0x03:
                        for(j=0;j<=3;j++) //pos3角度接收 
                                    {
                                        pos3.Receive_Val[j]=SHU1[j+1];
                                    }
                                   posBi[3]=pos3.Act_val;   
                                break;     
                                case 0x04:
                        for(j=0;j<=3;j++) //pos4角度接收 
                                    {
                                        pos4.Receive_Val[j]=SHU1[j+1];
                                    }
                                   posBi[4]=pos4.Act_val;   
                                break;     
                                case 0x05:
                        for(j=0;j<=3;j++) //pos5角度接收 
                                    {
                                        pos5.Receive_Val[j]=SHU1[j+1];
                                    }
                                   posBi[5]=pos5.Act_val;   
                                break;     
                                case 0x06:
                        for(j=0;j<=3;j++) //pos6角度接收 
                                    {
                                        pos6.Receive_Val[j]=SHU1[j+1];
                                    }
                                   posBi[6]=pos6.Act_val;   
                                break;
                                case 0x07://模式控制
                                      MODE=SHU1[1]-0x30;                                                         
                            }                                     
                        }
                        conunt = 0;
                        i = 0;
                    }
                    break;
            }    

    大家可以看见,本帅哥的处理逻辑是一个字节一个字节地进行,这里的逻辑是用来接收上位机发来的6个角度的,在上位机先将角度(小数)放在共用体的float 类型成员变量中,然后发送角度的 unsigned char 类型成员变量

    共用体定义如下:

    typedef union
    {
        unsigned char Receive_Val[3];
        float Act_val;
    }u8toointt;

    一个小数4个字节,所以对应4个字符型变量储存,然后32这边也定义一个共用体,用unsigned char 类型成员变量去接收,解出他的float 类型成员变量,便是我想要的角度了,怎么样,这一波我帅吧?

    突然发现跑题了,来看看我们是怎么解决中断只进去一次的问题的:

    官方给的中断接收的逻辑是写在回调函数里的,为什么写在回调函数里面呢?

    看这篇文章:(14条消息) 那些我们一起踩过的STM32HAL库的串口坑_我又不会射雕的博客-CSDN博客

    大概意思就是当有中断发送,硬件自动触发然后调用一系列函数,调用到 UART_Receive_IT()函数后,便会关闭中断!!!也就是串口看起来就只能进入一次中断!

    有的小可爱可能会问我为什么我能一直进中断呢?我试过,当上位机发送很快,且每次发送的字节数较少时(大概1个),我怎么配置他都能进中断!可能UART_Receive_IT()函数关闭中断的条件是中断触发的间隔时间吧,这点我没细看~

    当然有小可爱可能会说我像官方例程那样写,就什么问题都没有,我说小可爱,你可真可爱,没问题你来看我这篇文章干嘛,让我火吗???如果是,那给我点赞吧,不谢!我很帅!

    回归正题:

    注意看我的UART2_IRQHandler(void)函数里面接收函数用的HAL_UART_Receive_IT(&Uart2_Handle,(uint8_t *)ces, 1)!=HAL_OK

    还有一种接收函数是HAL_UART_Receive(&huart2,&Res,1,1000);

    它们两个处理名字差了三个字符外有什么区别呢?

    关键点来了:

    一起来看这篇文章:(14条消息) STM32采用HAL库HAL_UART_Receive_IT()多次开启的问题_暖暖_的_纠结的博客-CSDN博客_hal_uart_receive_it

    无情的文章搬运小天才(滑稽)~

    没看懂?解释一下我的理解:

    HAL_UART_Receive函数为非阻塞式接收,HAL_UART_Receive_IT()为阻塞式接收,说人话就是调用HAL_UART_Receive_IT()函数,一旦中断来了就能接收(前提是中断使能了),而HAL_UART_Receive则不一样,用在接收的地方卵用没有,简直消磨帅哥的时间~哼~

    所以我们使用HAL_UART_Receive_IT()函数,如果我们需要判断接收超时怎么办?我去官方例程copy了一下自己看上面 (^-^)

    这样写以后,帅哥再也不用担心H7串口进不去中断了,完美避开回调函数的写法,帅哥可高兴了,马上去食堂买一个水煮玉米奖励自己~~~

    然后你肯定想要移植,我这个工程肯定不会完全给你,但是可以给你这个串口接收的文件,欢迎期待我的github链接~

    展开全文
  • stm32串口的中断接收

    2021-04-09 10:30:21
    在找中断服务函数,使用了USART1就用1的函数,定义为void类型 USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);//得到中断标志函数 USART_ReceiveData(USART1);//串口数据接收函数

    一,ustart.c函数

    (一)结构体的配置

    1.GPIO口的配置

    PA9与PA10串口的配置----输出输入引脚

    2.USART,收发器结构体的配置

    3.NVIC,中断控制器结构体的配置

    (二)串口的中断配置

    USART_ITConfig(USART1,USART_IT_RXNE, ENABLE);//USART_IT_RXNE接收数据寄存器非空标志位;因为使用的是中断接收作用,所以来判断接收数据寄存器是否为空

     

    (三)中断优先级的配置

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//在设置“抢占优先级”和“子优先级”之前,要配置好优先级组,即这个函数

    二,main.c

    编写中断服务函数,使用了USART1就用1的函数,定义为void类型

    →→

     

        USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);//得到中断标志函数
     

        USART_ReceiveData(USART1);//串口数据接收函数

    #include "stm32f10x.h"
    #include "usart.h"
    #include <stdio.h>
    void usart_demo(void)
    {
    	GPIO_InitTypeDef  GPIOinitStruct;
    	USART_InitTypeDef USARTinitStruct;
    	
    	NVIC_InitTypeDef nvic_init;//配置中断控制器的结构体
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断优先级组的配置
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    	//PA9 
    	GPIOinitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    	GPIOinitStruct.GPIO_Pin=GPIO_Pin_9;
    	GPIOinitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIOinitStruct);
    
    	//PA10 
    	GPIOinitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    	GPIOinitStruct.GPIO_Pin=GPIO_Pin_10;
    	GPIO_Init(GPIOA, &GPIOinitStruct);
    	
    	//串口配置
    	USARTinitStruct.USART_BaudRate=115200;
    	USARTinitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    	USARTinitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
    	USARTinitStruct.USART_Parity=USART_Parity_No;
    	USARTinitStruct.USART_StopBits=USART_StopBits_1;
    	USARTinitStruct.USART_WordLength=USART_WordLength_8b;
    	USART_Init(USART1, &USARTinitStruct);
    	USART_Cmd(USART1,ENABLE);
    
    
    	//中断配置,ITConfig
    	USART_ITConfig(USART1,USART_IT_RXNE, ENABLE);
        //USART_IT_RXNE接收数据寄存器非空标志位
    
    	//串口中断配置
    	nvic_init.NVIC_IRQChannel=USART1_IRQn;//通道
    	nvic_init.NVIC_IRQChannelCmd=ENABLE;//
    	nvic_init.NVIC_IRQChannelPreemptionPriority=1;//
    	nvic_init.NVIC_IRQChannelSubPriority=1;
    
    	NVIC_Init(&nvic_init);//初始化函数
    
    
    }
    
    
    
    
    
    
    void USART_SendByte(USART_TypeDef* USARTx, uint16_t data)
    {
    	USART_SendData(USARTx, data);
    	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
    }
    
    
    
    void USART_SendStr(USART_TypeDef* USARTx, char *str)//定义的输出字符串的函数
    	uint16_t i=0;
    	do
    	{
    		USART_SendByte(USARTx, *(str + i));
    		i++;
    	}
    	while(*(str + i) != '\0');
    	
    	while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
    	
    	
    }
    /*【见七.3 https://blog.csdn.net/weixin_46965692/article/details/115250655】*/
    
    int fputc(int num,FILE *f)//Öض¨ÏòÊä³öº¯Êý
    {
    	USART_SendData(USART1, (uint8_t)num);
    	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    	
    	return (num);
    
    }	
    
    #include "stm32f10x.h"
    #include "led.h"
    #include "shakeLight.h"
    #include "exti.h"
    #include "usart.h"
    #include <stdio.h>
    void delay(uint16_t time)
    {
    	uint16_t x;
    	while(time --)
    	{
    		x=1200;
    		while(x--);
    	}
    }
    
    int main()
    {
    	
    	LED_demo();
    	usart_demo();
    	GPIO_SetBits(GPIOC, GPIO_Pin_13);
    	while(1)
    	{
    	}
    	
    	
      
    }
    void USART1_IRQHandler(void)
    {
    	char temp;//定义一个char类型,用来接收串口发送过来的字符数据
    	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//等于RESET的时候是没有发生中断;不等于RESRT就是发生了中断
    	{
    		temp=USART_ReceiveData(USART1);//接收数据
    		if(temp=='K')
    		{
    			GPIO_ResetBits(GPIOC, GPIO_Pin_13);//开灯
    			USART_SendStr(USART1,"deng kai le");//串口输出东西
    		}
    		if(temp=='G')
    		{
    			GPIO_SetBits(GPIOC, GPIO_Pin_13);
    			USART_SendStr(USART1,"deng guang ba");
    		}
    	}
    
    }

     

    展开全文
  • 本文介绍串口中断接收不定长字符串的方法。将串口1配置接收中断使能、空闲中断使能来接收不定长数据。 也就是在配置串口中断的时候使能接收中断和空闲中断。如下: ... USART_ITConfig(USART1, USART_IT_RXNE, ...

    一、应用简介

    本文介绍串口中断接收不定长字符串的方法。将串口1配置接收中断使能、空闲中断使能来接收不定长数据。
    也就是在配置串口中断的时候使能接收中断和空闲中断。如下:

    ...
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);	
    ...
    

    USART_IT_RXNE:接收中断,串口每收到一个字节就会产生一个此中断。
    USART_IT_IDLE:空闲中断,总线上在一个字节的时间内没有再接收到数据的时候发生的。
    之后在串口中断处理函数中分别判断处理2种中断就好了,如下:

    // 接收数组大小
    #define  RECEIVE_BUF_SIZE           255
    
    uint8_t g_usart1RxFlag = 0;							// 串口1接收标志0-未接受1-接收
    uint8_t  g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   	// 串口1接收缓冲  
    uint16_t g_uart1Len = 0;							// 串口1接收长度  
    /**
     @brief USART1中断
     @param 无
     @retval 无
    */
    void USART1_IRQHandler(void)  
    {  
    	// 接收中断的时候收集数据包
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
        {
            USART_ClearITPendingBit(USART1, USART_IT_RXNE); //只USART_ReceiveData也可以
    
            g_uart1ReceiveBuff[g_uart1Len] = USART_ReceiveData(USART1);
    
            g_uart1Len++;
        }
        // 空闲中断的时候说明串口没数据了,收集完成
        else if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET)
        {
            USART1->SR;
            USART1->DR;
    		// 标志位,代表有数据,此数据放到main处理去,不要放中断处理。我只打印一下
            g_usart1RxFlag = 1;
    		printf("shoudao1:%s", g_uart1ReceiveBuff);
    
        }
    } 
    

    最后,main函数,如下

    int main(void)
    {
    	...
        while (1)
        {
    		// 数据处理
            if(g_usart1RxFlag == 1)
    		{
    			// 数据处理,这里添加用户自定义处理,处理g_uart1ReceiveBuff后清空
    			
    
    			g_usart1RxFlag = 0;
    			g_uart1Len = 0;
    			memset(g_uart1ReceiveBuff, 0x00, sizeof(g_uart1ReceiveBuff));
    		}	
    		vTaskDelay(1);   /* 1ms启动读一次 */
        }
    	...
    }
    

    二、实例

    bsp_usart.h

    /**===========================================================================
      @file     bsp_usart.h
      @brief    本文件是用于串口驱动
      @author   青梅煮久
      @version  r0.1
      @date     2021/04/26
    ----------------------------------------------------------------------------
      Remark: (备注描述)
    	串口1的驱动。
    	串口1:用于日志打印、指令配置
    ----------------------------------------------------------------------------
                                    History
    ----------------------------------------------------------------------------
      <Date>     | <Version> | <Author>       | <Description>
    -------------|-----------|----------------|---------------------------------
      2021/04/26 | r0.1      | 青梅煮久        | 创建
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    ============================================================================*/
    #ifndef __BSP_USART_H
    #define	__BSP_USART_H
    
    /*********************************************************************
     * INCLUDES
     */
    #include "stm32f10x.h"
    #include <stdio.h>
    
    /*********************************************************************
     * DEFINITIONS
     */	
    // 接收数组大小
    #define  RECEIVE_BUF_SIZE           255
    
    /** 
    * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
    * 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
    * 2-修改GPIO的宏
    */
    /********************************串口1**********************************/
    #define  DEBUG_USARTx                   USART1
    #define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
    #define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
    #define  DEBUG_USART_BAUDRATE           115200
    
    #define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
    #define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
        
    #define  DEBUG_USART_TX_GPIO_PORT       GPIOA   
    #define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_9
    #define  DEBUG_USART_RX_GPIO_PORT       GPIOA
    #define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_10
    
    #define  DEBUG_USART_IRQ                USART1_IRQn
    #define  DEBUG_USART_IRQHandler         USART1_IRQHandler
    
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    extern uint8_t g_usart1RxFlag;							// 串口1接收标志0-未接受1-接收
    extern uint8_t  g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   // 串口1接收缓冲  
    extern uint16_t g_uart1Len;								// 串口1接收长度  
    /*********************************************************************
    * API FUNCTIONS
    */
    void USART1_Config(void);
    
    #endif /* __BSP_USART_H */
    
    

    bsp_usart.c

    /**===========================================================================
      @file     bsp_usart.h
      @brief    本文件是用于串口驱动
      @author   青梅煮久
      @version  r0.1
      @date     2021/04/26
    ----------------------------------------------------------------------------
      Remark: (备注描述)
    	串口1的驱动。
    	串口1:用于日志打印、指令配置
    ----------------------------------------------------------------------------
                                    History
    ----------------------------------------------------------------------------
      <Date>     | <Version> | <Author>       | <Description>
    -------------|-----------|----------------|---------------------------------
      2021/04/26 | r0.1      | 青梅煮久        | 创建
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    -------------|-----------|----------------|---------------------------------
                 |           |                |
    ============================================================================*/
    
    /*********************************************************************
     * INCLUDES
     */
    #include "bsp_usart.h"
    #include "stm32f10x.h"
    #include "string.h" 
    
    static void NVIC_Configuration(void);
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */
    uint8_t g_usart1RxFlag = 0;							// 串口1接收标志0-未接受1-接收
    uint8_t  g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   	// 串口1接收缓冲  
    uint16_t g_uart1Len = 0;							// 串口1接收长度  
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief  USART1 GPIO 配置,工作参数配置
     @param  无
     @retval 无
    */
    void USART1_Config(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    
    	// 打开串口GPIO的时钟
    	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    	
    	// 打开串口外设的时钟
    	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
    	
    	/*
    	*  配置串口
    	*  USART1_TX -> PA9 , USART1_RX ->	PA10
    	*/	
    	// 将USART Tx的GPIO配置为推挽复用模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
    
    	// 将USART Rx的GPIO配置为浮空输入模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
    	
    	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	USART_InitStructure.USART_Parity = USART_Parity_No ;
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	USART_Init(DEBUG_USARTx, &USART_InitStructure);
    
    	// 串口中断优先级配置
    	NVIC_Configuration();
    	
    	// 使能串口中断
    	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
    	USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);	
    	
    	// 使能串口
    	USART_Cmd(DEBUG_USARTx, ENABLE);	   
    
    }
    
    /**
     @brief 发送一个字节
     @param pUSARTx -[in] 串口
     @param ch -[in] 发送数据
     @retval 无
    */
    void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
    {
    	/* 发送一个字节数据到USART */
    	USART_SendData(pUSARTx,ch);
    		
    	/* 等待发送数据寄存器为空 */
    	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
    }
    
    /**
     @brief 发送8位的数组
     @param pUSARTx -[in] 串口
     @param array -[in] 发送数据
     @param num -[in] 发送长度
     @retval 无
    */
    void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
    {
      uint8_t i;
    	
    	for(i=0; i<num; i++)
      {
    	    /* 发送一个字节数据到USART */
    	    Usart_SendByte(pUSARTx,array[i]);	
      
      }
    	/* 等待发送完成 */
    	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
    }
    
    /**
     @brief 发送字符串
     @param pUSARTx -[in] 串口
     @param str -[in] 发送数据
     @retval 无
    */
    void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
    {
    	unsigned int k=0;
      do 
      {
          Usart_SendByte( pUSARTx, *(str + k) );
          k++;
      } while(*(str + k)!='\0');
      
      /* 等待发送完成 */
      while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
      {}
    }
    
    /**
     @brief 发送一个16位数
     @param pUSARTx -[in] 串口
     @param ch -[in] 发送数据
     @retval 无
    */
    void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
    {
    	uint8_t temp_h, temp_l;
    	
    	/* 取出高八位 */
    	temp_h = (ch&0XFF00)>>8;
    	/* 取出低八位 */
    	temp_l = ch&0XFF;
    	
    	/* 发送高八位 */
    	USART_SendData(pUSARTx,temp_h);	
    	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    	
    	/* 发送低八位 */
    	USART_SendData(pUSARTx,temp_l);	
    	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
    }
    
    /**
     @brief 重定向c库函数printf到串口,重定向后可使用printf函数
    */
    int fputc(int ch, FILE *f)
    {
    		/* 发送一个字节数据到串口 */
    		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
    		
    		/* 等待发送完毕 */
    		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
    	
    		return (ch);
    }
    
    /**
     @brief 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
    */
    int fgetc(FILE *f)
    {
    		/* 等待串口输入数据 */
    		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
    
    		return (int)USART_ReceiveData(DEBUG_USARTx);
    }
    
    /**
     @brief USART1中断
     @param 无
     @retval 无
    */
    void USART1_IRQHandler(void)  
    {  
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
        {
            USART_ClearITPendingBit(USART1, USART_IT_RXNE); //只USART_ReceiveData也可以
    
            g_uart1ReceiveBuff[g_uart1Len] = USART_ReceiveData(USART1);
    
            g_uart1Len++;
        }
        else if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET)
        {
            USART1->SR;
            USART1->DR;
    
            g_usart1RxFlag = 1;
    		printf("shoudao1:%s", g_uart1ReceiveBuff);
    
        }
    } 
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief  配置嵌套向量中断控制器NVIC
     @param  无
     @retval 无
    */
    static void NVIC_Configuration(void)
    {
    	NVIC_InitTypeDef NVIC_InitStructure;
      
    	/* 嵌套向量中断控制器组选择 */
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    	/* 配置串口的 NVIC设置*/
    	NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    
    }
    
    
    

    main.c

    #include "bsp_usart.h"
    
    int main(void)
    {
    	...
    	USART1_Config();
    	...
        while (1)
        {
    		// 数据处理
            if(g_usart1RxFlag == 1)
    		{
    			// 数据处理,这里添加用户自定义处理,处理g_uart1ReceiveBuff后清空
    			
    
    			g_usart1RxFlag = 0;
    			g_uart1Len = 0;
    			memset(g_uart1ReceiveBuff, 0x00, sizeof(g_uart1ReceiveBuff));
    		}	
    		vTaskDelay(1);   /* 1ms启动读一次 */
        }
    	...
    }
    

    • 由 青梅煮久 写于 2021 年 04 月 26 日

    展开全文
  • LWIP中断接收调试

    2020-12-30 15:03:19
    在POLL模式转为中断模式的时候发现ping时间很久而且经常超时,屏蔽掉如下耗时的打印代码就好了 PRINT_INFO("receive frame %d len buffer : %s\n", len, buffer);
  • 请教大家关于CAN中断接收的问题。

    千次阅读 2020-12-24 11:49:58
    我现在是让一个板子一直发消息,另一个板子产生接收中断,进入接收中断服务程序。但是一直进不去。还请大家帮忙看看问题出在哪里?可能就是一语惊醒梦中人啊。下面这部分是发送程序。应该没什么问题,在串口显示是...
  • 51命令接收
  • ESP8266 Arduino 串口中断接收 #include <ESP8266WiFi.h> String rx_data; void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); Serial.println("start: "); } ...
  • 空闲中断 //空闲中断 void USART1_IRQHandler(void) { unsigned int data; if(USART_GetITStatus(TEST_UART,USART_IT_RXNE) != RESET) { rx_buff[rx_cnt] = USART_ReceiveData(TEST_UART); rx_cnt++; } if(USART_...
  • STM32HAL库USART中断接收不定长数据——空闲中断法STM32cubeMX软件配置好串口中断,导出工程并打开,定义串口接收缓冲区和接收长度的全局变量:uint8_tRX_data[1000];uint16_tRX_len;在main函数的初始化中开启IDLE...
  • 文章目录软硬件型号1. CUBE配置2. 代码添加 软硬件型号 STM32F103RCT开发板 STM32CUBEMX+KEIL5编程 STM32F1 1.8.3 库版本 ...#define USART_REC_LEN 200 //定义最大接收字节数 200 #define EN_USART1_RX 1 //使能
  • 此次工程效果:串口115200波特率,接收串口助手XCOM发送的数据并发送回XCOM 本次配置的工程链接在最下方,有需要自取。 0基础可以从第一个教程开始阅读 STM32CUBEMX配置教程(一)基础配置 STM32CUBEM
  • 多年已过,楼主肯定解决了,但是一直没有说一下怎么解决的,我说一下吧附上f030的代码1、初始化千万不要初始化就打开IDLE中断2、在串口接收中断中打开IDLE中断3、正确清楚IDLE中断。void USART1_Config(void){GPIO_...
  • 原标题:STC12C5A60S2 串口中断接收程序#define UART0_BUF_LEN 32 int UART1_Recv_count; //接收计数bit UART1_Overflow_Flag; //缓冲区满标志idata uchar UART1_Recv_BUF[UART0_BUF_LEN]; //串口接收缓冲区//串口...
  • STM32串口中断接收一帧数据

    千次阅读 2021-01-03 22:52:57
    STM32串口中断接收一帧数据 IDLE即串口空闲中断,串口收到一帧数据后,发生的中断。比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据。因为只有接收...
  • 配置串口通信模式时设置成了同步模式,改成异步模式就好了 有些串口调试助手(如win10商店的免费的串口调试助手)不能正确显示接收的字符,需要换调试软件。
  • 五个串口发送与中断接收例程 一. 串口通信简介 串口通信的原理网上教程一大堆了,入坑单片机的必会串口,这里就不多说了。唯一值得一提的就是STM32是有USART和UART之分的。UART就是通用异步收发传输器(Universal ...
  • CubeMX,HAL库使用串口发送和中断接收一、CubeMX界面配置二、MDK代码 不得不说HAL库和标准库相比确实简单多了。。。 一、CubeMX界面配置 选择完 异步通讯模式 后,其余默认即可。 打开串口中断 二、MDK代码 在/* ...
  • #include "DSP28x_Project.h"// Device Headerfile and Examples Include Fileinterrupt void scibTxFifoIsr(void);//fifo发送中断函数interrupt void ...//fifo接收中断函数void scib_fifo_init(void);//scib ...
  • 在使用STM32的串口接收数据的时候,我们常常会使用接收中断的方式来接收数据,常用的是RXNE。这里分享另一种接收数据的方式——IDLE中断(PS:本文的例子运行在STM32F103ZET6上)。一、IDLE中断什么时候发生?IDLE就是...
  • 在实际工作上,串口连续中断接收最灵活与实用。 如果项目上使用了RTOS,那么串口非空闲中断接收+消息队列就是一个完美的组合。如果项目上没有使用RTOS,那么串口非空闲中断接收+ringbuffer算法(FIFO)也是一个完美...
  • //接收帧缓存,自己定义大小 uint8_t USART1_STA = 0; bool USART1_Receive_Flag = false; uint8_t res = 0; (2)在MX_USART1_UART_Init()最后添加HAL_UART_Receive_IT(&huart1, &res...
  • TI 280045使用SPI FIFO中断接收数据总结

    千次阅读 2021-01-14 21:15:50
    1 基本方案 最近调试STM32与DSP双芯片SPI通讯的调试,总结...为了避免DSP SPI接收FIFO中的数据溢出导出的数据错帧问题,使用了FIFO接收中断,当SPI 接收FIFO深度达到16级时,产生一个中断任务,在中断中读取FIFO缓存
  • 文章目录前言第一步:用于保存数据的数组和变量第二步:定义串口初始化函数第三步:定义串口数据发送函数第四步:重写中断服务函数第五步:在 main 函数中处理接收到的数据并通过串口发送出去 前言 测试过程中使用...
  • 被HAL库中断接收丢失首字节的这个问题折磨了四天了,今天终于解决了,觉得有必要记录一下。 问题是这样的:刚开始上电后,用串口助手给串口1发送一帧数据(有帧头帧尾的),正常接收,继续发送,也正常接收,之后当...
  • 在我目前负责的项目,之前是使用串口接收中断来判断是否完成数据接收,项目的坑货前任最开始的方法是在串口接收中断里面清除标志,在微系统的数据处理里面对标志位++,判断如果两次没进到接收中断就认为接收数据完成...
  • 目标:使用USART中断接收数据 一、准备工作 硬件平台:正点原子探索者开发板 二、使用步骤 1.新建工程 依次点击File-->New-->STM32 Project: 2.工程配置 保持工程默认配置: 代码...
  • 在usart.c上增加配置NVIC优先级中断控制器 NVIC_InitTypeDef Nvic_init; //misc.h NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC中断组 //3.配置NVIC中断控制器 在misc.h里 Nvic_init.NVIC_...
  • // 在中断接收数据。该方法需要放在 USART2_IRQHandler 函数中。 void (*processData)(void); // 处理数据、需要自己填写如何解析,处理数据。该方法可放在 while 循环或 recvDataInIntrrupt 中。 }objUsart2;//...
  • 本文默认读者已经对can和stm32的can收发器有了一定...代码设置can的滤波器和中断(如果用到中断的话)。现具体讲述着两大部分。 1.1 图形化界面设置can的波特率和相关工作模式 首先,使能can模块; 接着调整“Presc

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 256,097
精华内容 102,438
关键字:

中断接收