/****************************************************************************** * 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()0 c& i) l+ P% l * 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输 * 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,- e9 ]* x0 {6 `1 w( ` * 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART% M, H1 e/ Q4 z3 Q) y. x4 j) E * 整个过程无需用户程序干预,用户只需启动DMA传输传输即可 * 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止+ I, l* W! [& H k6 U0 _% z8 p * 串口依然发送,表明DMA传输是一个独立的过程。 * 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理, t( e3 Y) y+ J1 S/ \9 _ * 作者:jjldc(九九)) t2 q+ U1 U% f/ Y5 w! Q$ d * 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6 *******************************************************************************/1 S. { _ ^2 e& n /* Includes ------------------------------------------------------------------*/' ` s* M0 c6 [. S: d/ M* O #include "stm32f10x_lib.h"+ t* G' }* s% d7 }8 \6 a i: \& C #include "stdio.h"; d2 c1 r' @/ s/ u4 } /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/& ] c! t' A. A, E #define USART1_DR_Base 0x40013804 /* Private macro -------------------------------------------------------------*/" w' l |* z: ^; x; G6 {) ]; E /* Private variables ---------------------------------------------------------*/$ n" Z' _2 v7 ^2 r #define SENDBUFF_SIZE 10240 vu8 SendBuff[SENDBUFF_SIZE];" `) Q' H, {0 q4 H: ` vu8 RecvBuff[10];6 v7 p7 X- l- t3 M0 s2 @" }3 c vu8 recv_ptr;& q# Q8 r5 i$ }" W( c4 j: o+ P; g6 S /* Private function prototypes -----------------------------------------------*/) p0 H' e5 l9 d void RCC_Configuration(void);0 ^$ p% `, S. b/ A void GPIO_Configuration(void);6 h% J$ P5 F7 c* Z, q7 C w# K void NVIC_Configuration(void);- F8 p6 q8 m8 }9 \" [! C void DMA_Configuration(void); void USART1_Configuration(void);2 Y# u+ I: ?, h3 d7 c' u int fputc(int ch, FILE *f);0 V3 r9 H! `+ s" j void Delay(void); /* Private functions ---------------------------------------------------------*/ /*******************************************************************************6 H* Z: ?# p$ r# m4 } * Function Name : main * Description : Main program. * Input : None * Output : None * Return : None *******************************************************************************/% R4 ^- ^ |" v int main(void) {5 C) Z8 _4 g ?' g' e2 E u16 i; #ifdef DEBUG debug(); #endif9 u5 k" h$ M9 _) j" e, N recv_ptr = 0; RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration();8 e8 F! k' [/ f% v! Y: ` DMA_Configuration(); USART1_Configuration();) ^$ p- Y8 h3 |7 o" U) u9 K' M( N6 {& M& Z printf("\r\nSystem Start...\r\n");' C/ Z& ^+ j. G printf("Initialling SendBuff... \r\n"); for(i=0;i<SENDBUFF_SIZE;i++) {$ t1 G; n) ^' j) g/ w4 ] SendBuff = i&0xff; } printf("Initial success!\r\nWaiting for transmission...\r\n"); //发送去数据已经准备好,按下按键即开始传输9 P& P9 z2 a& J% O$ i+ b( w/ h while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3)); printf("Start DMA transmission!\r\n"); U- t- L8 Z3 v3 U1 i //这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //开始一次DMA传输!, J% B4 e+ @: c" _8 F* D DMA_Cmd(DMA1_Channel4, ENABLE);. y5 K- Z. _ t //等待DMA传输完成,此时我们来做另外一些事,点灯. C$ M' e: h) j% N, a //实际应用中,传输数据期间,可以执行另外的任务 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) { LED_1_REV; //LED翻转 Delay(); //浪费时间 }4 r$ e, z" N) o: X //DMA传输结束后,自动关闭了DMA通道,而无需手动关闭 //下面的语句被注释 //DMA_Cmd(DMA1_Channel4, DISABLE); printf("\r\nDMA transmission successful!\r\n");3 e( ?9 ?% q0 T1 J/ s /* Infinite loop */ while (1) { } B# h: i% {1 d) T9 w0 {- h; z }/ s3 G" @8 W$ ?7 N( _9 _( U' [ /******************************************************************************* * Function Name : 重定义系统putchar函数int fputc(int ch, FILE *f) * Description : 串口发一个字节 * Input : int ch, FILE *f) n# s* C2 y1 F | * Output : * Return : int ch/ R8 O. F# c$ C * 这个是使用printf的关键! j9 ?6 O5 H( o* j- h *******************************************************************************/ int fputc(int ch, FILE *f) {; f! I/ Z9 w' m2 S& N' U9 [ //USART_SendData(USART1, (u8) ch);: s) k9 E# P' x0 \; {7 a USART1->DR = (u8) ch;! `1 ~6 z7 _" l$ g7 a/ G /* Loop until the end of transmission */ while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) {0 y( d" x+ z, L2 f* O- a8 ~/ k4 ] } return ch; } /*******************************************************************************) W8 ~7 R6 p$ }$ J4 ~5 z$ f. h * Function Name : Delay: }* l- |$ [0 S% @, \1 r * Description : 延时函数 * Input : None+ S* M" y+ k9 ?$ l; J' H5 |# y * Output : None * Return : None+ g; g; v4 q* [" u g5 J: W *******************************************************************************/6 M2 \0 v% C; | x9 M% n void Delay(void) {: ~) O( g0 t. W4 S* N8 `1 G u32 i;" N# ^' g( }! I0 q: p9 E- p for(i=0;i<0xF0000;i++); return;: o) [( i# Q/ L- }0 }5 Z/ c; U } /******************************************************************************* * Function Name : RCC_Configuration * Description : 系统时钟设置 * Input : None * Output : None3 y8 H, Q0 F9 W5 _5 S& x * Return : None *******************************************************************************/ void RCC_Configuration(void)0 g" o5 ]# H& ]' G2 ^' O q% C3 Z1 Q {! M: |( ?/ G, ~3 w ErrorStatus HSEStartUpStatus; //使能外部晶振 RCC_HSEConfig(RCC_HSE_ON); //等待外部晶振稳定( p% `+ j8 N* h7 `2 z5 p R9 U HSEStartUpStatus = RCC_WaitForHSEStartUp(); //如果外部晶振启动成功,则进行下一步操作 Z0 f7 u' m& y/ T8 S- x if(HSEStartUpStatus==SUCCESS)# K. ]) o$ W2 Q( \3 ]; g* z2 @ {- A) {9 ?0 k3 A4 d5 N- ]$ I/ e //设置HCLK(AHB时钟)=SYSCLK RCC_HCLKConfig(RCC_SYSCLK_Div1);8 _1 | i8 ]3 l$ V4 U+ w: q3 v" H //PCLK1(APB1) = HCLK/2 RCC_PCLK1Config(RCC_HCLK_Div2);% t, D% N; u6 `8 t. `4 M4 | //PCLK2(APB2) = HCLK RCC_PCLK2Config(RCC_HCLK_Div1);1 `! K6 U6 n. i //FLASH时序控制' [9 i) U+ H% n* e" |: y3 | //推荐值:SYSCLK = 0~24MHz Latency=0 // SYSCLK = 24~48MHz Latency=1 // SYSCLK = 48~72MHz Latency=24 u9 `- ^9 A- v2 b* J4 d0 X FLASH_SetLatency(FLASH_Latency_2);" ` N& |2 ]- s* b; t1 P$ E //开启FLASH预取指功能 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);5 ]5 }1 W! ~( D# @" V( A1 L //PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz! r9 J3 |* ]& {; @ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);, i2 R+ `9 O" s //启动PLL RCC_PLLCmd(ENABLE);# k9 U' E$ [# Y- P+ h# q2 q //等待PLL稳定 q- E. a' _; A; k$ T! |3 x/ V while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);) J8 Q0 r" z( X5 V8 n3 P' e- f //系统时钟SYSCLK来自PLL输出 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //切换时钟后等待系统时钟稳定2 ^: W4 H! _6 Q while(RCC_GetSYSCLKSource()!=0x08); /*' x- r, U1 ~( R) s+ K //设置系统SYSCLK时钟为HSE输入: Q6 m) Y& l" Q0 D6 ?3 n ?8 b RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); //等待时钟切换成功 while(RCC_GetSYSCLKSource() != 0x04);; Y$ p9 B- o" e. B2 d' |+ t/ s */ e/ C: d+ j3 Y) U( N# z } //下面是给各模块开启时钟 //启动GPIO& A' ^. P7 X3 c7 T1 m RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \* q2 R( P6 H3 w# W8 a b RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\ ENABLE); //启动AFIO RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //启动USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);+ H+ P. w- q* n& ?' I8 G! E) o# B: v //启动DMA时钟6 d. C1 f! H) V% W RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);4 k8 m* I! O+ ] S! u$ I }7 \, h' |# [6 P /******************************************************************************* * Function Name : GPIO_Configuration& ^# ~( b1 m3 q0 R- j * Description : GPIO设置: a8 E" Q% d _$ ` * Input : None * Output : None+ j# Z8 j: a3 T; Z; l! B% g * Return : None *******************************************************************************/ void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; //PC口4567脚设置GPIO输出,推挽 2M& v& L( w5 J: ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;5 ]! |7 _7 `$ M. U$ e4 a1 ]3 i- h5 _* x GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC, &GPIO_InitStructure);' n6 k/ w. `' }1 d& Z# N6 m' T. { //KEY2 KEY3 JOYKEY //位于PD口的3 4 11-15脚,使能设置为输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\; O$ L9 @8 o& i' U; Y$ B GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;9 K: h/ d7 a3 ?2 C GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;: M% B, F7 D( j. m- [ GPIO_Init(GPIOD, &GPIO_InitStructure); //USART1_TX8 e0 X- ` w2 V# f- E! b; r" ^) i GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; y+ W7 K1 z7 M @! B GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;! y- s' B, h# p$ v( P! r GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX. b8 M' O0 Y( } GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;! T* z9 w2 \2 Y- E GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;1 A$ [) F8 z* i4 J GPIO_Init(GPIOA, &GPIO_InitStructure); }0 \' c* ~' B7 d /******************************************************************************* * Function Name : NVIC_Configuration * Description : NVIC设置" |' B; w. A6 f/ t8 f * Input : None * Output : None( z# m: }4 Q% K) c" @ * Return : None# C) ]$ s& O9 s. |( [. D, T3 M *******************************************************************************/. g% ^. h2 o. H$ z2 L! C& { void NVIC_Configuration(void)2 H2 e2 w2 d4 a- ^. \ { NVIC_InitTypeDef NVIC_InitStructure; #ifdef VECT_TAB_RAM, D) O _0 M) M! `; ^! j // Set the Vector Table base location at 0x20000000 a$ X4 }7 w( U* B NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */2 n, z! b+ q" Q8 [5 J // Set the Vector Table base location at 0x08000000 NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //串口接收中断打开 2 k+ }5 U0 r. b8 I; Q0 s. M NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;$ U& b9 t0 X5 D6 C2 {2 R( Q0 U! d, \ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;5 i' |0 b( m0 r8 D NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /******************************************************************************* * Function Name : USART1_Configuration- t. T4 o3 \( n: V# [* G * Description : NUSART1设置/ e0 o( S4 a8 ]7 T$ C" S * Input : None * Output : None( @) O% F' l; G- h l; I2 E# G * Return : None *******************************************************************************/3 y! `; J+ Z ~- x5 U1 v$ w0 S% _ void USART1_Configuration(void)$ z# S a; I% ~$ u$ T {% u% ^2 R/ }( n9 ]+ \ USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600;; X- L0 g% |/ L1 v% V USART_InitStructure.USART_WordLength = USART_WordLength_8b;/ M3 F5 J0 @: ^ USART_InitStructure.USART_StopBits = USART_StopBits_1;( w( ?9 H9 k& t/ E+ ^ USART_InitStructure.USART_Parity = USART_Parity_No; R+ [& m* o, J. a* t. I+ c USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);' q2 {4 [5 U d* Y USART_Cmd(USART1, ENABLE);1 I) u$ }+ P* E8 e; s$ v }. [: |! x$ h4 ?( ~5 m" c void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure; //DMA设置:) A2 i4 h, L- N4 ] //设置DMA源:内存地址&串口数据寄存器地址" R' w2 j3 t" O6 l! J+ k9 ? //方向:内存-->外设 //每次传输位:8bit //传输大小DMA_BufferSize=SENDBUFF_SIZE0 e" j/ S6 x5 P, _$ S //地址自增模式:外设地址不增,内存地址自增1- v* D" P8 u6 a+ P1 R //DMA模式:一次传输,非循环 //优先级:中# P. z) }2 v6 {; Z0 Y- Z DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;& E' k* A) A' i% L6 c& ~ DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;$ G( w0 z' @" j3 z DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;: R* R/ d% p' L) q7 ? DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;3 O3 T p! Q. q0 k DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;: ~; o- U# Z( T: w DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;! \/ s2 m6 |$ |4 o DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; T/ I: ]0 @: R% y2 x DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure); } |
STM32固件库分享,超全系列整理
STM32的CAN FD位定时设置注意事项
基于STM32将移植 SBSFU 到 STM32G070过程分享
基于STM32G030 RAM不够用经验分享
STM32G070在OLED上移植U8G2单色GUI
【经验分享】STM32 IAP+Ymodem功能实现(参考官方代码)
【经验分享】STM32的SPI问题
【经验分享】STM32 的加密实现
STM32G070—使用platformio+arduino
STM32G0-Platformio平台下使用libopencm3库