发个 STM8L的 USART DMA 可变长发送接收,使用串口空闲

2019-12-26 18:53发布

在官方例子基础上改的。
使用串口空闲中断可以接收小于接收缓冲区数量的数据。
接收和发送全都通过DMA。

*************************main**********************************

#include "stm8l15x.h"

#define USART_DMA_CHANNEL_RX   DMA1_Channel2
#define USART_DMA_CHANNEL_TX   DMA1_Channel1
#define USART_DMA_FLAG_TCRX    (uint16_t)DMA1_FLAG_TC2
#define USART_DMA_FLAG_TCTX    (uint16_t)DMA1_FLAG_TC1
#define USART_DR_ADDRESS       (uint16_t)0x5231  /* USART1 Data register Address */

#define USART_BAUDRATE         (uint32_t)9600
#define DATA_TO_TRANSFER       (countof(TxBuffer) - 1)
#define DATA_TO_RECEIVE        (uint8_t) 0x20      //这个值要设的比最多可能的值大一些
#define countof(a)            (sizeof(a) / sizeof(*(a)))

#define LED1_PORT GPIOE
#define LED1_PIN  GPIO_Pin_7
#define KEY_PORT  GPIOD
#define KEY_PIN   GPIO_Pin_1
#define KEY_DOWN  GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == RESET

uint8_t TxBuffer[] = " USART Example:USART-Hyperterminal communication using DMA. Enter your Text ";
uint8_t RxBuffer[DATA_TO_RECEIVE] = {0};

bool TX_DMA_READY_FLG = FALSE;
bool TX_DMA_ENABLE_FLG = FALSE;
unsigned char RxDMADatCount = 0;
unsigned char RxRECCount = 0;
/* Private function prototypes -----------------------------------------------*/
static void CLK_Config(void);
static void DMA_Config(void);
void Delay (uint32_t nCount);
void LEDToggle(void);
/* Private functions ---------------------------------------------------------*/

void Set_485(void);

void DMA_START_TX(void);
void DMA_START_RX(void);


static void CLK_Config(void)
{
  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
  CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);
}

void main(void)
{
  CLK_Config();
  GPIO_Init(LED1_PORT,LED1_PIN,GPIO_Mode_Out_PP_Low_Slow);
  GPIO_Init(KEY_PORT,KEY_PIN,GPIO_Mode_In_PU_No_IT);
  Set_485();
  DMA_Config();
  TX_DMA_READY_FLG  = TRUE;
  enableInterrupts();
  USART_Cmd(USART1, ENABLE);

  
    while (1)
  {
   if(KEY_DOWN)TX_DMA_ENABLE_FLG = TRUE;else TX_DMA_ENABLE_FLG = FALSE;//按键以后开始DMA发送
    Delay((uint32_t)0xFFF); //模拟CPU在处理某些事务
   if(TX_DMA_READY_FLG && TX_DMA_ENABLE_FLG)
   {
    TX_DMA_READY_FLG = FALSE;//在DMA-TC中断中会将此置 true 后改为按键发动
    DMA_START_TX();//开启TX_DMA发送数据
    LEDToggle();//翻转LED灯
   }
   RxRECCount =DATA_TO_RECEIVE - RxDMADatCount;//接收到的数据个数,用总的接收区减去DMA接收后还余下未接受的个数

  }
}


static void DMA_Config(void)
{
  /* Deinitialize DMA channels */
  DMA_GlobalDeInit();

  DMA_DeInit(DMA1_Channel1);
  DMA_DeInit(DMA1_Channel2);

  /* DMA channel Rx of USART Configuration */
  DMA_Init(USART_DMA_CHANNEL_RX, (uint16_t)RxBuffer, (uint16_t)USART_DR_ADDRESS,
           DATA_TO_RECEIVE, DMA_DIR_PeripheralToMemory, DMA_Mode_Normal,
           DMA_MemoryIncMode_Inc, DMA_Priority_Low, DMA_MemoryDataSize_Byte);

  /* DMA channel Tx of USART Configuration */
  DMA_Init(USART_DMA_CHANNEL_TX, (uint16_t)TxBuffer, (uint16_t)USART_DR_ADDRESS,
           DATA_TO_TRANSFER, DMA_DIR_MemoryToPeripheral, DMA_Mode_Normal,
           DMA_MemoryIncMode_Inc, DMA_Priority_High, DMA_MemoryDataSize_Byte);

  /* Enable the USART Tx/Rx DMA requests */
  USART_DMACmd(USART1, USART_DMAReq_TX, ENABLE);
  USART_DMACmd(USART1, USART_DMAReq_RX, ENABLE);

   DMA_ITConfig(USART_DMA_CHANNEL_TX, DMA_ITx_TC, ENABLE);//使能TC中断
  
  /* Global DMA Enable */
  DMA_GlobalCmd(ENABLE);

  /* Enable the USART Tx DMA channel */
// DMA_Cmd(USART_DMA_CHANNEL_TX, ENABLE);
  /* Enable the USART Rx DMA channel */
  //DMA_Cmd(USART_DMA_CHANNEL_RX, ENABLE);         
}

void Set_485(void)
{
  GPIO_Init( GPIOC, GPIO_Pin_4, GPIO_Mode_Out_PP_High_Fast);
  GPIO_ResetBits(GPIOC, GPIO_Pin_4);

  CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);

  GPIO_ExternalPullUpConfig(GPIOC, GPIO_Pin_2 | GPIO_Pin_3, ENABLE);

  USART_DeInit(USART1);

  USART_Init(USART1, (uint32_t)9600, USART_WordLength_8b, USART_StopBits_1,
             USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Rx | USART_Mode_Tx));

  USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
  
  USART_Cmd(USART1, DISABLE);

}

void Delay(uint32_t nCount)
{
  /* Decrement nCount value */
  while (nCount != 0)
  {
    nCount--;
  }
}
void LEDToggle(void)
{
  GPIO_ToggleBits(LED1_PORT,LED1_PIN);
}

void DMA_START_TX(void)
{
   DMA_Cmd(USART_DMA_CHANNEL_TX, DISABLE);
   DMA_ClearFlag(DMA1_FLAG_TC1);
   DMA_ClearFlag(DMA1_FLAG_HT1);
   DMA_SetCurrDataCounter(USART_DMA_CHANNEL_TX, DATA_TO_TRANSFER);
   DMA_Cmd(USART_DMA_CHANNEL_TX, ENABLE);
}
void DMA_START_RX(void)
{   DMA_ClearFlag(DMA1_FLAG_TC2);
    DMA_ClearFlag(DMA1_FLAG_HT2);
    DMA_Cmd(USART_DMA_CHANNEL_RX, DISABLE);
    DMA_SetCurrDataCounter(USART_DMA_CHANNEL_RX, DATA_TO_RECEIVE);
    DMA_Cmd(USART_DMA_CHANNEL_RX, ENABLE);
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
5条回答
lovepig200
2019-12-26 20:38
本帖最后由 lovepig200 于 2017-8-7 15:06 编辑

******************************it.c*************************************

/* Includes ------------------------------------------------------------------*/
#include "stm8l15x_it.h"
   
   
   
   
extern void DMA_START_RX(void);
extern void LEDToggle();
extern void DMA_START_TX();
extern bool TX_DMA_READY_FLG;
extern unsigned char RxDMADatCount;
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/

#ifdef _COSMIC_
/**
  * @brief Dummy interrupt routine
  * @param  None
  * @retval None
  */
INTERRUPT_HANDLER(NonHandledInterrupt, 0)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
}
#endif

/**
  * @brief TRAP interrupt routine
  * @param  None
  * @retval None
  */
INTERRUPT_HANDLER_TRAP(TRAP_IRQHandler)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
}


INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler, 2)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
  TX_DMA_READY_FLG = TRUE; //TC传送完成后,置位READY
  DMA_ClearITPendingBit(DMA1_IT_TC1);
}

INTERRUPT_HANDLER(USART1_RX_TIM5_CC_IRQHandler, 28)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
if(USART_GetITStatus(USART1,  USART_IT_IDLE) != RESET)
{
unsigned char temp;
temp = USART1->SR;temp = USART1->DR;//IDLE清零需要依次读SR 和DR 寄存器
USART_ClearITPendingBit(USART1,  USART_IT_IDLE);
RxDMADatCount =  DMA_GetCurrDataCounter(DMA1_Channel2);
DMA_START_RX();//重新开启串口DMA接收模式
}
}

一周热门 更多>