Algumas precauções para desenvolver stm32 com Cubemx e biblioteca HAL

Descrição breve

Ele registra principalmente algumas configurações e opções comumente usadas. Se forem encontrados erros, discuta-os na área de comentários.

Solução para o problema que o downloader não consegue baixar no projeto gerado pelo STM32CubeMX F1

Blog de Mculover666

Configuração de fonte de relógio RCC do Cubemx

Ao usar o cubo para configurar o relógio, existem duas opções:
Insira a descrição da imagem aqui

  • Fonte de relógio BYPASS (ignorar fonte de relógio)
    refere-se aos componentes da unidade de relógio interno do chip que são necessários quando os cristais externos não são usados ​​e os sinais de relógio são importados diretamente do mundo externo. É como se os componentes do drive dentro do chip fossem ignorados.
  • Ressonador Cristal / Cerâmico (oscilador de cristal externo)
    Esta fonte de relógio é formada pela cooperação de um cristal externo passivo e o circuito de acionamento do relógio interno do MCU.Tem um certo tempo de inicialização e alta precisão.

Onde o HSE é um OSC_IN和OSC_OUTcristal de contato esquemático de hardware
Insira a descrição da imagem aqui
LSE é um diagrama esquemático de um OSC32_IN和OSC32_OUTcristal de contato de hardware
Insira a descrição da imagem aqui

Configure a árvore do relógio

A árvore do relógio deve se referir a se o hardware usa um relógio interno ou um oscilador de cristal externo, e então configurar a frequência desejada de acordo com o manual de dados do chip ou manual de referência, e não pode exceder a frequência máxima exigida no manual.
Árvore do relógio da placa RM C
A imagem acima mostra a árvore do relógio da versão C oficial do Robomaster da rotina

Pinos GPIO de configuração do Cubemx

Insira a descrição da imagem aqui

  • Nível de saída GPIO: nível de saída padrão

  • Modo GPIO:
    saída push pull open dreno
    Ootput open dreno push-pull para
    entender o dreno aberto e saída push-pull

  • GPIO Pull-up / Pull-down: resistência pull-up e pull-up, deve ser configurado de acordo com o hardware.

  • Velocidade máxima de saída:
    GPIO_SPEED_LOW; (2) 2MHz
    GPIO_SPEED_MEDIUM; (25) 12,5 MHz ~ 50
    MHz GPIO_SPEED_FAST; (50) 25MHz ~ 100 MHz
    GPIO_SPEED_HIGH; (100) 50 MHz ~ 200 MHz

Configuração da porta serial UART

Insira a descrição da imagem aqui

  • Modo:
    comunicação assíncrona assíncrona Comunicação
    síncrona síncrona

Geralmente não é usado em outros modos

Interrupção da porta serial UART

Precisa redefinir a função de retorno de chamada de interrupção

Modo DMA da porta serial UART

Insira a descrição da imagem aqui

  • Modo:
    Normal: Modo normal, você precisa habilitar continuamente o envio e recebimento.
    Circular: Modo circular

  • Largura de dados: dados transmitidos por DMA de uma só vez

  • Endereço de incremento: se o endereço aumenta após o DMA transferir dados de largura de dados

Definição de macro de ativação de DMA de porta serial :
__HAL_DMA_ENABLE, __HAL_DMA_ENABLE_IT.

Função de retorno de chamada de interrupção de DMA da porta serial :
Insira a descrição da imagem aqui

O
transceptor da porta serial pode usar a função DMA ao mesmo tempo. No entanto, dois canais DMA diferentes são necessários. Há uma relação correspondente entre a porta serial e o canal DMA. Consulte o manual de referência.

Canal
DMA O DMA tem vários canais. Embora cada canal possa receber solicitações de vários periféricos, ele só pode receber um ao mesmo tempo, não vários ao mesmo tempo.

Cubemx configura o DMA para habilitar automaticamente a interrupção global do DMA, mas é melhor habilitá-lo novamente com _HAL_DMA_ENABLE_IT.
Se você aceitar o mesmo comprimento de dados todas as vezes no modo de loop, poderá definir o registro DMA_SxNDTR. Por segurança, você também pode redefini-lo todas as vezes. Ele pode ser usado para verificar manualmente se há um erro de comprimento de dados em um quadro de transmissão de dados. Lembre-se de desativar o DMA antes de configurar
Insira a descrição da imagem aqui

Recepção ociosa da porta serial + buffer duplo DMA

  • Depois que a porta serial recebe um quadro de dados (um quadro de dados consiste em vários bytes, defina a quantidade de dados a receber por vez), o IDLEbit será definido como 1.
  • O buffer duplo mudará a área de armazenamento de destino após receber um quadro de dados (no final da transferência DMA). Dessa forma, se o quadro anterior de dados estiver sendo processado, o novo quadro de dados não será sobrescrito neste momento.
  • Os dados aqui são todos dados de comprimento fixo.
  • O modo MTM (memória para memória) do DMA não oferece suporte a buffers duplos. O buffer duplo deve ser definido para o modo cíclico.
  1. Configurar buffer duplo
    Método 1:
    Use a função de biblioteca HAL HAL_DMAEx_MultiBufferStart_IT()e, a seguir, julgue o buffer atual na função de interrupção. (Alguns chips podem não suportar esta função de biblioteca HAL, como f103). Ainda preciso habilitar o DMA.

    Método 2:
    Registre o modo de buffer duplo e, em seguida, julgue o buffer atual na função de interrupção. Tome USART3 como exemplo, lembre-se de modificar o fluxo DMA e o registro uart.

    //enable the DMA transfer for the receiver request
    //使能DMA串口接收
    SET_BIT(huart3.Instance->CR3, USART_CR3_DMAR);
    
    //enalbe idle interrupt
    //使能空闲中断
    __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
    
    //disable DMA
    //失效DMA
    __HAL_DMA_DISABLE(&hdma_usart3_rx);
    while(hdma_usart3_rx.Instance->CR & DMA_SxCR_EN)
    {
        __HAL_DMA_DISABLE(&hdma_usart3_rx);
    }
    
    //外设寄存器
    hdma_usart3_rx.Instance->PAR = (uint32_t) & (USART3->DR);
    //memory buffer 1
    //内存缓冲区1
    hdma_usart3_rx.Instance->M0AR = (uint32_t)(rx1_buf);
    //memory buffer 2
    //内存缓冲区2
    hdma_usart3_rx.Instance->M1AR = (uint32_t)(rx2_buf);
    //data length
    //一帧的数据长度
    hdma_usart3_rx.Instance->NDTR = dma_buf_num;
    //enable double memory buffer
    //使能双缓冲区
    SET_BIT(hdma_usart3_rx.Instance->CR, DMA_SxCR_DBM);
    
    //enable DMA
    //使能DMA
    __HAL_DMA_ENABLE(&hdma_usart3_rx);
    

    Os dois métodos acima podem ser adicionados aHAL_UART_MspInit()中的用户代码处

  2. CTBit de julgamento na interrupção da porta serial
    Primeiro julgue se a área de buffer atual é Memory0 ou Memory1, se for 0, os dados em 1 serão processados; se for 1, a informação em 0 será processada, e o processamento não afetam a recepção de dados em outro buffer:

//串口中断
void USART3_IRQHandler(void)
{
    if(huart3.Instance->SR & UART_FLAG_RXNE)//接收到数据
    {
        __HAL_UART_CLEAR_PEFLAG(&huart3);//清除校验错误中断位,如果使能对应中断会进入
    }
    else if(USART3->SR & UART_FLAG_IDLE)//检测到总线空闲
    {
        static uint16_t this_time_rx_len = 0;

        __HAL_UART_CLEAR_PEFLAG(&huart3);//清除校验错误中断位,如果使能对应中断会进入

        if ((hdma_usart3_rx.Instance->CR & DMA_SxCR_CT) == RESET)//DMA_SxCR寄存器的CT位为0,处理缓冲区1数据
        {
            /* Current memory buffer used is Memory 0 */
    
            //disable DMA
            //失效DMA
            __HAL_DMA_DISABLE(&hdma_usart3_rx);

            //get receive data length, length = set_data_length - remain_length
            //获取接收数据长度,长度 = 设定长度 - 剩余长度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;

            //reset set_data_lenght
            //重新设定数据长度
            hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
            
            //set memory buffer 1
            //设定缓冲区1
            hdma_usart3_rx.Instance->CR |= DMA_SxCR_CT;  
                      
            //enable DMA
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart3_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                sbus_to_rc(sbus_rx_buf[1], &rc_ctrl);
            }
        }
        else	//当前缓冲区为1,处理缓冲区,0数据
        {
            /* Current memory buffer used is Memory 1 */
            //disable DMA
            //失效DMA
            __HAL_DMA_DISABLE(&hdma_usart3_rx);

            //get receive data length, length = set_data_length - remain_length
            //获取接收数据长度,长度 = 设定长度 - 剩余长度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;

            //reset set_data_lenght
            //重新设定数据长度
            hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;

            //set memory buffer 0
            //设定缓冲区0
           hdma_usart1_rx.Instance->CR &= ~(DMA_SxCR_CT);
// 或者改为           DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
//如果不是usart3,记得修改DMA流
 
            //enable DMA
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart3_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                //处理遥控器数据
                sbus_to_rc(sbus_rx_buf[0], &rc_ctrl);
            }
        }
    }
}

A interrupção inativa é usada aqui, e a interrupção inativa precisa ser habilitada com antecedência.
Você pode consultar o buffer duplo da biblioteca HAL

Após o teste, o uso da HAL_DMAEx_MultiBufferStart_IT()função ainda precisa substituir o buffer na interrupção. Eu estava errado antes. Habilitar o bit de buffer duplo irá de fato trocar automaticamente o buffer. Como a rotina de controle remoto da placa C é um pouco problemática, o julgamento está errado.

IIC

Half-duplex
Funções de biblioteca HAL comumente usadas:
HAL_I2C_Mem_Read () e HAL_I2C_Mem_Write (), etc., consulte a documentação de ajuda da biblioteca HAL

SPI


Funções de biblioteca HAL full-duplex comumente usadas:
HAL_SPI_Transmit ()

O IIC e o SPI são usados ​​principalmente para comunicação com uma pequena quantidade de dados, e a condução real de diferentes periféricos pode exigir embalagem adicional.

POSSO

TIM

Insira a descrição da imagem aqui

  • Modo mestre-escravo, raramente usado

Insira a descrição da imagem aqui

  • Relógio interno: relógio interno, ou seja, fonte de relógio

  • Entrada de disparo externo ETR2 (ETR) (aplicável apenas a TIM2, 3, 4)
    Insira a descrição da imagem aqui

  • PSC: Prescaler, a fonte do relógio é o relógio do temporizador através deste prescaler. A frequência do relógio do temporizador é igual à frequência da fonte do relógio / (psc + 1)
    Insira a descrição da imagem aqui

  • Modo do contador: para cima, para baixo e três contagens alinhadas ao centro. O cronômetro básico só pode fazer uma contagem progressiva.

  • ARR: valor de recarga automática, período do temporizador T = (ARR + 1) * (1 / frequência do relógio do temporizador) = (ARR + 1) * (PSC + 1) / 72M

  • Divisão do relógio interno: O fator de divisão do relógio, necessário para configurar o tempo morto.

  • auto-reload-preload: auto-reload) enable

  • Saída de acionamento dos parâmetros TRGO (TRGO)

Para fazer o cronômetro funcionar, chame a função de biblioteca HAL_TIM_Base_Start ().
Para usar a interrupção do cronômetro, chame a função de biblioteca HAL_TIM_Base_Start_IT ().
Ambos PSC e ARR devem primeiro ser decrementados em 1, porque de acordo com o manual de referência, o valor do registro é o valor definido mais 1

TIM_PWM

Insira a descrição da imagem aqui

  • Pulso: Defina o ciclo de serviço e defina o valor do registro CCR. Ciclo de trabalho P = CCR / (ARR + 1)

TIM_ENCODER

Apenas TIM1 e TIM2 têm modo de codificador
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

  • Modo do codificador: T1 e T2 // O codificador captura na borda ascendente de TI1 TI2, a borda ascendente de TI1 adiciona e subtrai o contador de acordo com o nível de TI2 e a borda ascendente de TI2 adiciona e subtrai o contador de acordo com o nível de TI1.
    Polaridade: Aumento
    // O parâmetro TIM_EncoderMode é o modo, contagem monofásica (pode apenas refletir a velocidade) ou contagem bifásica (velocidade e direção)
    // TI1 e TI2 são ambos contados na borda, e se é para cima ou para baixo depende da rotação para a frente ou reversa
    // A captura ocorre na borda de subida IC1 e IC2

Consulte o manual para o modo de codificador

ADC / DAC

  • ADC_mode: Use apenas um ADC para configurar como modo independente e use vários ADCs (ADC1 / 2/3) para configurar como
  • Alinhamento de dados: alinhamento de dados à esquerda / direita
  • Modo de conversão de varredura: modo de varredura, a ser ativado ao usar vários canais
  • Modo de conversão contínua: conversão contínua / conversão única, quando configurada como uma conversão única, os dados serão convertidos apenas uma vez e irá parar, e será acionado novamente
  • Ativar conversões regulares: conversão regular,
  • Habilitar conversões injetadas: conversões injetadas

Habilite ADC antes de começar:
HAL_ADC_Start ou HAL_ADC_Start_IT

Acho que você gosta

Origin blog.csdn.net/lqysgdb/article/details/112966705
Recomendado
Clasificación