STM32 是一款基于ARM Cortex-M3内核的32位MCU,主频最高可达72M。最近因为要在车机上集成TPMS功能, 便开始着手STM32的开发工作,STM32F10x系列共有5个串口(USART1~USART5),支持DMA方式通信,DMA方式由于不需要CPU的参与,而是直接由DMA控制器完成串口数据的读写,因而可以很大程度的提高CPU的利用率。在使用STM32串口之前需要做一系列的初始化工作:
1.RCC(复位和时钟控制寄存器)初始化,启用GPIO、DMA、USART时钟。
2.NVIC(嵌套向量中断控制寄存器)初始化,完成各个硬件中断的配置。
3.USART初始话,配置串口,设置DMA通道等。
4.DMA初始化,完成DMA的配置。
最后是使能USART和DMA。下面是通过DMA的方式从串口USART1接收数据,STM32工作后串口数据由DMA控制器接收存到指定buffer,读取数据直接从DMA buffer中读取即可。发送数据采用非DMA方式,首先将待发送的数据存入到发送队列,然后在任务循环中将队列中的数据发送给USART1。实例代码如下:
1 //********************************************************************************************** 2 // STM32F10x USART Test 3 // compiler: Keil UV3 4 // 2011-03-28 , By friehood 5 //********************************************************************************************** 6 static int8u rDMABuffer[64]; // DMA buffer 7 static int16u rDMARear = sizeof(rDMABuffer); 8 9 static int8u USART_RevBuf[64]; // 串口接收buffer 10 static int8u USART_SndBuf[64]; // 串口发送buffer 11 static int8u Head=0,Tail=0; // 发送buffer的头尾 12 13 14 // 串口任务 15 void Task_USART(void) 16 { 17 int16u end; 18 if (USART1->SR & (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE)) 19 { 20 USART_ReceiveData(USART1); 21 } 22 23 // DMA接收 24 end = DMA_GetCurrDataCounter(DMA1_Channel5); 25 /*if((sizeof(rDMABuffer)-end)>0) 26 dbgprt("DMA available datalen=%d/n",sizeof(rDMABuffer)-end); */ 27 while(rDMARear != end) 28 { 29 USART_receive(rDMABuffer[sizeof(rDMABuffer)-rDMARear]); 30 if (!(--rDMARear)) 31 { 32 rDMARear = sizeof(rDMABuffer); 33 } 34 } 35 36 //发送 37 if(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == SET) 38 { 39 int8u chr; 40 // 从发送队列取出一个字符 41 if(PopFront(&chr)) 42 { 43 USART_SendData(USART1, chr); 44 dbgprt("USART_SendData:0x%02x/n",chr); 45 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) 46 { 47 } 48 } 49 } 50 } 51 52 53 // USART串口初始化 54 void dev_USART_init(void) 55 { 56 USART_InitTypeDef USART_InitStructure; 57 GPIO_InitTypeDef GPIO_InitStructure; 58 DMA_InitTypeDef DMA_InitStructure; 59 60 /* DMA1 Channel5 (triggered by USART1 Rx event) Config */ //参见 STM32 datasheet 61 DMA_DeInit(DMA1_Channel5); 62 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; 63 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)rDMABuffer; 64 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 65 DMA_InitStructure.DMA_BufferSize = sizeof(rDMABuffer); 66 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 67 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 68 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 69 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 70 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 71 DMA_InitStructure.DMA_Priority = DMA_Priority_Low; 72 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 73 DMA_Init(DMA1_Channel5, &DMA_InitStructure); 74 75 USART_InitStructure.USART_BaudRate = 9600; 76 USART_InitStructure.USART_WordLength = USART_WordLength_8b; 77 USART_InitStructure.USART_StopBits = USART_StopBits_1; 78 USART_InitStructure.USART_Parity = USART_Parity_No; 79 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 80 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 81 82 //配置IO: GPIOA9和GPIOA10分别作为串口TX、RX端。 见STM32 datasheet 83 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 84 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 85 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 86 GPIO_Init(GPIOA,&GPIO_InitStructure); 87 88 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 89 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 90 GPIO_Init(GPIOA,&GPIO_InitStructure); 91 92 /* Configure USART1 */ 93 USART_Init(USART1, &USART_InitStructure); 94 /* Enable USART1 DMA Rxrequest */ 95 USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); 96 /* Enable DMA1 Channel5 */ 97 DMA_Cmd(DMA1_Channel5, ENABLE); 98 /* Enable the USART1 */ 99 USART_Cmd(USART1, ENABLE); 100 } 101 102 // 向串口发送数据 103 void USART_send(const int8u *pBuf, int8u len) 104 { 105 int i; 106 if(pBuf == NULL) 107 { 108 return; 109 } 110 // 将数据压入到发送队列 111 dbgprt("USART_PushBack:"); 112 for(i=0;i<len;i++) 113 { 114 PushBack(*pBuf); 115 dbgprt("0x%02x ",*pBuf); 116 pBuf++; 117 } 118 dbgprt("/n"); 119 } 120 121 // 向发送队列尾部插入一个字节 122 void PushBack(int8u byte) 123 { 124 USART_SndBuf[Tail++]= byte; 125 if(Tail >= ARRAYSIZE(USART_SndBuf)) 126 Tail = 0; 127 if(Tail == Head) 128 Head = Tail+1; 129 } 130 131 // 从发送队列头部取出一个字节 132 bool PopFront(int8u *byte) 133 { 134 if(Head >= ARRAYSIZE(USART_SndBuf)) 135 Head = 0; 136 if(Head == Tail) 137 return FALSE; 138 *byte = USART_SndBuf[Head++]; 139 return TRUE; 140 } 141 142 // 处理接收到的串口数据 143 void USART_receive(int8u byte) 144 { 145 // Treate received data 146 // Place Code here 147 // ... 148 } 149 150 // CRC校验 151 bool CheckCRC(const int8u *str, int8u len, const int8u *crcstr) 152 { 153 int8u checkSum; 154 if(str == NULL || crcstr== NULL) 155 return FALSE; 156 GetCRC(str,len,&checkSum); 157 if(checkSum != *crcstr) 158 return FALSE; 159 else 160 return TRUE; 161 } 162 163 // 获取CRC 164 bool GetCRC(const int8u *str, int8u len, int8u *crcstr) 165 { 166 int8u i; 167 int8u checkSum; 168 if(str == NULL || crcstr== NULL) 169 return FALSE; 170 checkSum = *str; 171 for(i=1; i<len; i++) 172 { 173 checkSum ^= *(str+i); 174 } 175 *crcstr = checkSum; 176 return TRUE; 177 }