/****************************************************************************** * 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()6 e2 b- U4 F |: a- D * 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输 * 每当USART的发送缓冲区空时,USART模块产生一个DMA事件, * 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART5 D2 b; o" `7 r* I * 整个过程无需用户程序干预,用户只需启动DMA传输传输即可* e2 Q E0 K) n6 v * 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止2 }. e X6 ^2 t z9 L8 A * 串口依然发送,表明DMA传输是一个独立的过程。 * 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理: C: q& C+ w# h: Q * 作者:jjldc(九九)* }8 i% f, l0 b * 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT63 U- }$ Z1 a# |- C7 O% p, u *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_lib.h" #include "stdio.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/% L7 P4 P& f9 | #define USART1_DR_Base 0x40013804 /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ #define SENDBUFF_SIZE 10240, S, f: ^4 T5 ?7 n3 i8 t vu8 SendBuff[SENDBUFF_SIZE]; vu8 RecvBuff[10];, j4 ~, m% ^7 w vu8 recv_ptr; /* Private function prototypes -----------------------------------------------*/ void RCC_Configuration(void); void GPIO_Configuration(void);: C) T. R% J8 M- h7 [ void NVIC_Configuration(void);; ?6 b* i# s- o _3 K6 M9 t2 t, b& N0 v c void DMA_Configuration(void); void USART1_Configuration(void);/ `3 y4 h* ~5 y1 w5 k2 H$ a1 M int fputc(int ch, FILE *f);7 @- x- S, D, g3 ?* r$ l# l# U) o; c# w void Delay(void);1 R B h |9 T, {8 A /* Private functions ---------------------------------------------------------*/% y, h) i, q( s& K /******************************************************************************* * Function Name : main * Description : Main program.: ]' i) p$ O$ R * Input : None- ^7 l. p: N7 b' A * Output : None * Return : None# ^/ W; j, K' F *******************************************************************************/ int main(void) {3 s" F3 Z P. q& d& ?' k y u16 i;- j/ U7 c0 T2 X* b #ifdef DEBUG+ p* P$ G5 Y* q# l$ r. P( S debug(); #endif! ?; Z" v' R5 P recv_ptr = 0;- r. u5 }7 U D3 s" j( j) e% B$ F, i RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration();. T2 w% Y' H3 r0 y8 s9 v DMA_Configuration();! x, B, V( _6 Y1 a. \# Q7 l F USART1_Configuration(); printf("\r\nSystem Start...\r\n");& p% [8 ^7 P. o% f; Q) Y printf("Initialling SendBuff... \r\n");. g ^" ^4 t* }. C3 y for(i=0;i<SENDBUFF_SIZE;i++) {2 M y i5 t& ^: Q SendBuff = i&0xff; }) t& a/ }$ d# K7 T2 a printf("Initial success!\r\nWaiting for transmission...\r\n"); //发送去数据已经准备好,按下按键即开始传输 while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3)); printf("Start DMA transmission!\r\n"); //这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);% S) K9 o2 F. |# n' q' G; d" {. M S //开始一次DMA传输!$ v5 B& X( U! Y% z- }4 m; Y DMA_Cmd(DMA1_Channel4, ENABLE); //等待DMA传输完成,此时我们来做另外一些事,点灯 //实际应用中,传输数据期间,可以执行另外的任务 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) {* A9 W% g& o& W! z) I) B; F2 w LED_1_REV; //LED翻转 Delay(); //浪费时间. ?' M- @/ _& b8 L } @( ~+ Y$ I. a; e2 y$ L6 p0 P; l //DMA传输结束后,自动关闭了DMA通道,而无需手动关闭 //下面的语句被注释 //DMA_Cmd(DMA1_Channel4, DISABLE);( ]# }4 o; p. S printf("\r\nDMA transmission successful!\r\n"); /* Infinite loop */ i, c5 _: k- O8 C9 K9 B Y0 T while (1). E% h4 h/ j; c {* H* u. V* }, I1 p1 T. a }8 h2 R: W/ D1 l" v8 G$ I0 l, U } /*******************************************************************************( w n% b, ]7 `; H0 ^* u * Function Name : 重定义系统putchar函数int fputc(int ch, FILE *f) * Description : 串口发一个字节 * Input : int ch, FILE *f4 e1 g4 ~; _$ T2 U8 R * Output : * Return : int ch * 这个是使用printf的关键( R1 {$ ?& v. |, @( w: Y *******************************************************************************/ int fputc(int ch, FILE *f)$ |. w' U5 I" T/ O# h; p& V) z. M { //USART_SendData(USART1, (u8) ch); USART1->DR = (u8) ch;1 ^2 Y' J* O- [5 N1 }9 g. F /* Loop until the end of transmission */! |9 o# |2 o) }$ d3 x while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)+ w: h, K. u/ ?1 L/ j2 ? { }. X7 V$ Q2 ~/ B; g# D return ch;. x, D3 ~1 S. Z1 p. G5 Y4 d } /******************************************************************************* * Function Name : Delay * Description : 延时函数5 g, J& i* O: G9 N * Input : None' y7 ^4 z0 H0 }4 l2 X" @) d# @3 a; p7 B * Output : None * Return : None* J6 R6 R1 c% G) `4 t' o2 n *******************************************************************************/, j" K6 h+ F" r( U void Delay(void)6 E0 h6 V! h% `7 _2 ~ {. ]( M; R4 q8 {% N' Y- M7 _ u32 i;" B6 R" m& E9 h7 h& W for(i=0;i<0xF0000;i++);7 u. K, A! c6 [ return;- B) k' A. S, x! h2 h) C4 f6 k( {, l* T- U } /*******************************************************************************3 S, I( z$ M* l * Function Name : RCC_Configuration * Description : 系统时钟设置( Y3 _" O/ u1 v, N* d4 B6 t * Input : None * Output : None * Return : None' K M6 N, G. b *******************************************************************************/ void RCC_Configuration(void)1 X0 a& @$ u* c. J8 A. t {" W, [2 U3 z. O+ s/ N ErrorStatus HSEStartUpStatus; //使能外部晶振3 j7 h6 G9 o3 `1 c7 A RCC_HSEConfig(RCC_HSE_ON);0 ~* c" d' V4 r( V. I) I( y //等待外部晶振稳定 HSEStartUpStatus = RCC_WaitForHSEStartUp(); //如果外部晶振启动成功,则进行下一步操作 if(HSEStartUpStatus==SUCCESS) {" V" i7 @$ K* k //设置HCLK(AHB时钟)=SYSCLK: O# O: T6 ~% a RCC_HCLKConfig(RCC_SYSCLK_Div1); //PCLK1(APB1) = HCLK/2% g: c) }0 o) ]/ m+ V7 L RCC_PCLK1Config(RCC_HCLK_Div2);& r, |8 U4 H5 C! s/ v6 K4 V& w //PCLK2(APB2) = HCLK0 B0 q1 W% J+ i1 t' p RCC_PCLK2Config(RCC_HCLK_Div1); //FLASH时序控制) o l& `4 ~$ M //推荐值:SYSCLK = 0~24MHz Latency=0: D$ a% T& p# Y9 \6 _+ S9 u% r // SYSCLK = 24~48MHz Latency=1* g' h+ X4 w+ `" T" a' y6 i // SYSCLK = 48~72MHz Latency=2 FLASH_SetLatency(FLASH_Latency_2); //开启FLASH预取指功能 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //启动PLL8 n% @: S/ F2 s0 [ RCC_PLLCmd(ENABLE);7 ?3 E; ~0 v! }( |" \ m0 _ //等待PLL稳定 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);7 z+ x4 b( Z6 @% b% J* ^& X //系统时钟SYSCLK来自PLL输出9 y; R' h0 g! i1 j; F$ A RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);- [& i! A# }4 F6 B# g, u //切换时钟后等待系统时钟稳定 while(RCC_GetSYSCLKSource()!=0x08); /** d9 v8 I8 ^3 v+ y, C$ P //设置系统SYSCLK时钟为HSE输入7 F" R2 e3 d" q3 g5 V5 { RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);% C) e& B0 B3 E) m. g //等待时钟切换成功; |2 A! A! E# ?' R) D while(RCC_GetSYSCLKSource() != 0x04); */ } //下面是给各模块开启时钟) m2 t" W: R2 M* a& | //启动GPIO1 l6 y. g( t/ i. d RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \5 _* ?+ S5 x) N$ Y, e RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\1 k, j. U7 |% S' x7 f( r& ~4 F ENABLE); //启动AFIO \2 {8 k3 {5 w+ j/ Z2 Z RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);6 J1 u0 x8 `1 W8 H' l4 y //启动USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //启动DMA时钟" `. l1 O/ Q% c& @) z3 [ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);+ y8 J! T( e+ F; \: \. W } /*******************************************************************************/ `: S& R2 |& \) G( t# y; W- J- e! B * Function Name : GPIO_Configuration * Description : GPIO设置 * Input : None * Output : None4 j! C, A) o/ h, I * Return : None' U0 P, O9 O/ h" M *******************************************************************************/6 b3 m4 d- e6 w- ? void GPIO_Configuration(void)1 T \5 w, q! }8 f9 P3 R" a { GPIO_InitTypeDef GPIO_InitStructure; j N* k) x n: C& {0 \2 R //PC口4567脚设置GPIO输出,推挽 2M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;! o9 n; l" I/ `4 e* r GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC, &GPIO_InitStructure);( R) e, Z2 u3 p //KEY2 KEY3 JOYKEY. \& h" m7 Z7 t: f# Y4 r$ [9 a) E //位于PD口的3 4 11-15脚,使能设置为输入1 V- z# ]; D( }' Q9 _( { GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\ X* v" q4 V8 h GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;9 J; M3 V3 d4 ?* V* m5 l% `; C GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;- c) j3 l) q7 r GPIO_Init(GPIOD, &GPIO_InitStructure); p w* X" T y, h6 d" d& A //USART1_TX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;" H% Q1 ^. E5 f: v* D GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;' p ~3 ~/ _4 j8 G' U# H. x6 [3 m GPIO_Init(GPIOA, &GPIO_InitStructure);) _/ M8 ~3 D, c( ]5 A3 D; j } /*******************************************************************************5 T$ w O+ [! o1 h& m; ~ * Function Name : NVIC_Configuration2 @( m0 E$ P! ]& C0 d * Description : NVIC设置- Q l# Z8 ]: i2 Z * Input : None6 K2 z+ W" E4 g" b3 J' w" ] * Output : None * Return : None *******************************************************************************/ void NVIC_Configuration(void)0 C4 y2 G; r5 E' I0 ~6 m/ B { NVIC_InitTypeDef NVIC_InitStructure;- \0 z- {* q+ V% m5 s #ifdef VECT_TAB_RAM1 \0 T% @8 x" ] // Set the Vector Table base location at 0x200000003 G ^8 d/ a: N+ ]; m NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);! D1 C7 P- X1 A/ i0 C #else /* VECT_TAB_FLASH *// i' p6 j4 r4 S8 x! w; q9 _3 X. R // Set the Vector Table base location at 0x080000000 `1 L$ p+ w/ V4 ]% F NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);. w7 u5 x; a2 Z( a3 }) k9 Q9 M3 L #endif //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);. A( f( q. L s1 W2 j; `+ D //串口接收中断打开 1 w# b) [$ ~9 U. p2 ^( ], \ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }% G6 B% t# y+ L( {% m. \ /******************************************************************************* * Function Name : USART1_Configuration# @ E6 _- |6 V- C% n * Description : NUSART1设置 * Input : None * Output : None * Return : None# Y. ^6 @) x4 @4 i *******************************************************************************/3 g# }& q! e u2 b8 H' O( P void USART1_Configuration(void)% m: `) |1 g! B0 o1 K {2 S. {! G4 b3 d2 X4 Y USART_InitTypeDef USART_InitStructure;+ F) V% [9 F2 c5 a6 a- L. @ USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;( N1 j& @ C' V9 G5 q: n USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;. Q* m6 Q/ z- @/ r3 v5 e) Z USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);4 P( y, w9 `0 _" ^5 ?: B0 D) }* v USART_Cmd(USART1, ENABLE);# @1 w7 ~7 a3 q z$ B9 }; E7 [ } void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure; //DMA设置: //设置DMA源:内存地址&串口数据寄存器地址 //方向:内存-->外设 //每次传输位:8bit //传输大小DMA_BufferSize=SENDBUFF_SIZE8 F' E& h5 P9 n7 r& @. S //地址自增模式:外设地址不增,内存地址自增16 ^4 O" j# M3 r //DMA模式:一次传输,非循环! r! U6 t* Q& u' p$ I8 p/ l. t //优先级:中, V2 h6 h) Q* {9 @ DMA_DeInit(DMA1_Channel4); J0 m; N( H4 D# a: ~% p/ t) H( m DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;; e, S, j; X; m! a9 N DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;- h1 ~% H# i, Q DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;2 O9 E7 I' U& d, O DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;( h3 w; `+ P6 W0 g DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;$ ?$ Z2 c, T* T# W+ F' T DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;9 o: {6 f! M) v% ^ DMA_Init(DMA1_Channel4, &DMA_InitStructure);1 f6 v; w9 D+ @ }) B8 K B' D$ G8 X8 _0 Z6 W6 }5 \ |
X-NUCLEO-IKS4A1实现手势滑动
STM32G系列RS485自动收发控制以及自适应波特率实战
STM32G0系列ADC扫描序列模式解读
STM32固件库分享,超全系列整理
【经验分享】FPGA作为从机与STM32进行SPI协议通信---Verilog实现
【管管推荐】STM32经验分享篇
STM32G030F6P6基于HAL库模拟SPI驱动1.8寸TFT LCD屏幕
STM32的CAN FD位定时设置注意事项
基于STM32将移植 SBSFU 到 STM32G070过程分享
基于STM32G030 RAM不够用经验分享