4、USB调试模块

1、USB硬件初始化

底层初始化使用的CUBEMX,库函数版本F4_V1.25.具体配置如下

在这里插入图片描述在这里插入图片描述

2、USB函数封装

USB通信中真正的收发数据都是在USB中断中进行的,所以为了确认USB不会被其他中断打断,将USB的抢占优先级设定为0。

先说一下实现的大概思路吧。
只是发送(MCU -> PC)的话,用到了一个消息队列,一个线程。
1、创建一个消息队列tx_mq,一个发送线程tx_thread
2、用户想要发送消息的时候,将消息存入tx_mq中。存入的消息满足一定条件时将消息发送至tx_thread中进行发送
接受(PC->MCU)的话同理。先将接收到的消息存入接受的消息队列,然后转发到处理该消息的线程。

下面的就是用户将消息存入消息队列实现的代码。里面的信号量主要作用是 防止重入该函数。

#include "usbd_consolse.h"
#include "usbd_thread.h"


static uint8_t usbd_consolse_is_init = 0;
rt_sem_t  usbd_con_bin_sem = RT_NULL;
msg_t   message_to_print;
void usbd_console_Init()
{
    if(usbd_consolse_is_init) return;

    usbd_con_bin_sem = rt_sem_create("usbd_con_bin_sem", 1, RT_IPC_FLAG_FIFO);

    if(usbd_con_bin_sem != RT_NULL)
        usbd_consolse_is_init = 1;

}
int32_t usbd_console_put_char(uint8_t _ch)
{
    uint8_t isInInterrupt = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? 1 : 0;
    int delay_time = 0;

    if(!usbd_consolse_is_init) return 0;

    if(isInInterrupt)
    {
        delay_time = 0;
    }
    else
    {
        delay_time = RT_WAITING_FOREVER;
    }

    if(rt_sem_take(usbd_con_bin_sem, delay_time) == RT_EOK)
    {
        if(message_to_print.data_len < MSG_MAX_DATA_SIZE)	
        {
            message_to_print.data[message_to_print.data_len] = (uint8_t)_ch;
            message_to_print.data_len++;
        }

        if(_ch == '\n' || message_to_print.data_len >= MSG_MAX_DATA_SIZE)	
        {
            usbd_send_packet(&message_to_print);
            message_to_print.data_len = 0;
        }
    }

    rt_sem_release(usbd_con_bin_sem);

    return (uint8_t)_ch;
}
int32_t usbd_console_puts(char *_str)
{
    int ret = 0;

    while(*_str)
        ret |= usbd_console_put_char(*_str++);

    return ret;
}

上面说存入的消息满足一定条件时将消息发送至tx_thread中进行发送,这个条件就是上述代码中的if(_ch == '\n' || message_to_print.data_len >= MSG_MAX_DATA_SIZE)这句话。

#ifndef _USBD_CONSOLE__H_
#define _USBD_CONSOLE__H_
#include "main.h"

void    usbd_console_Init(void);
int32_t usbd_console_put_char(uint8_t ch);	            /* 输入一个字符到usbd_console缓冲区*/
int32_t usbd_console_puts(char *str);	                /* 输入一个字符串到usbd_console缓冲区*/

#endif /*_USBD_CONSOLE__H_*/

下面是具体的USB接受和实现的代码

#include "usbd_thread.h"
#include "usbd_consolse.h"
#include <stdio.h>
#include <string.h>

static rt_mq_t tx_mq = RT_NULL;
rt_mq_t rx_mq = RT_NULL;
static uint8_t usbd_thread_is_init = 0;
#define USBD_TX_QUEUE_SIZE 2
#define USBD_RX_QUEUE_SIZE 32

void usbd_uesr_hal_init(void)
{
    if(usbd_thread_is_init) return;

    tx_mq = rt_mq_create("usbd_send_mq", sizeof(msg_t), USBD_TX_QUEUE_SIZE, RT_IPC_FLAG_FIFO);
    rx_mq = rt_mq_create("usbd_recv_mq", sizeof(uint8_t), USBD_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO);

    if((tx_mq != RT_NULL) && (rx_mq != RT_NULL))
        usbd_thread_is_init = 1;
}
uint8_t usbd_send_packet(msg_t *_buf)
{
    if(_buf == NULL) return RT_ENOMEM;

    return rt_mq_send(tx_mq, _buf, sizeof(msg_t));
}

uint8_t usbd_recv_data()
{
    int8_t data = -1;
    rt_mq_recv(rx_mq, &data, sizeof(uint8_t), 50);
    return data;
}
char rt_hw_console_getchar(void)
{
    int ch = -1;
    ch = usbd_recv_data() & 0XFF;
    return (ch);
}
void usbd_rx_thread_entry(void *param)
{
    while(1)
    {
        //do something
        rt_thread_delay(200);
    }
}
void usbd_tx_thread_entry(void *param)
{
    extern uint8_t CDC_Transmit_FS(uint8_t * Buf, uint16_t Len);
    msg_t p_msg_queue;
    uint8_t sned_buf[MSG_MAX_DATA_SIZE] = {0};

    while(1)
    {
        if(rt_mq_recv(tx_mq, &p_msg_queue, sizeof(msg_t), RT_WAITING_FOREVER) == RT_EOK)
        {
            memcpy((void *)sned_buf, p_msg_queue.data, p_msg_queue.data_len);
            CDC_Transmit_FS(sned_buf, p_msg_queue.data_len);
        }
    }
}


#ifndef _USBLINK__H_
#define _USBLINK__H_
#include "main.h"
#include "usbd_consolse.h"

#define MSG_MAX_DATA_SIZE 128

typedef struct
{
    uint8_t  data[MSG_MAX_DATA_SIZE];
    uint32_t data_len;
}msg_t;
void usbd_uesr_hal_init(void);

uint8_t usbd_send_packet(msg_t *);

void usbd_rx_thread_entry(void *);
void usbd_tx_thread_entry(void *);

#endif /*usbd_thread.h*/

3、USB注册到RTT控制台

在将USB注册到RTT控制台的过程中,主要分为两部分,依次是发送和接收。 先说一下最简单的的发送。

参考RTT官网,要实现void rt_hw_console_output(const char *str)函数,具体的实现如下

void rt_hw_console_output(const char *str)
{
    rt_enter_critical();
    extern int32_t usbd_console_put_char(uint8_t _ch);
    char ch;   
    while(*str != '\0') 
    {  
        ch = *str;        
        if(ch == '\n')
        {
            ch = '\r';
            usbd_console_put_char(ch);
        }         
        usbd_console_put_char(*str);
        str++;
    }
    rt_exit_critical();
    /* empty console output */
}

主要的发送实体是函数usbd_console_put_char(*str);这里使用局部变量ch是为了补全\r\n,方便换行使用。

下面说一下具体的接收函数实现,依旧参考官网给出的例程,需要实现rt_hw_console_getchar()函数,具体实现如下。

uint8_t usbd_recv_data()
{
    int8_t data = -1;
    rt_mq_recv(rx_mq, &data, sizeof(uint8_t), 50);
    return data;
}
char rt_hw_console_getchar(void)
{
    int ch = -1;
    ch = usbd_recv_data() & 0XFF;
    return (ch);
}

之后需要在usbd_cdc_if.c文件中修改CDC_Receive_FS函数为如下

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
    /* USER CODE BEGIN 6 */
    uint8_t i = 0;
    uint8_t data = 0;
    extern rt_mq_t rx_mq;

    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);
    for(i = 0; i < *Len; i++)
    {
        data = Buf[i];
        rt_mq_send(rx_mq, &data, sizeof(uint8_t));
    }
    return (USBD_OK);
    /* USER CODE END 6 */
}

具体思路就是将接受的函数一个一个的传入接受的消息队列,然后从消息队列中挨个读出。上述的代码实现只满足了最基本的功能,其实可以将接收消息的长度发送到消息队列,方便对数据进行处理。因为前期只是用于调试,所以并没有实现该功能,且RX_THREAD线程里面并未进行任何操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值