/******************************************************************************# A& f; h% [7 B* m' O* g5 l; R9 w * 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData(): `+ s3 u0 t8 O! m* Q9 X3 t/ x3 ^ * 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输 * 每当USART的发送缓冲区空时,USART模块产生一个DMA事件, * 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART! T- w. C4 M5 N8 u" O# K * 整个过程无需用户程序干预,用户只需启动DMA传输传输即可 * 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止' ]" ^" P! F7 G5 l# S: a/ S/ b( j * 串口依然发送,表明DMA传输是一个独立的过程。; l6 v2 L4 J2 W3 R * 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理 * 作者:jjldc(九九)# I3 V3 t% [3 b$ W& t8 v * 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6: i$ Q7 x$ H; |' A8 A) L- X# o" e *******************************************************************************/ /* Includes ------------------------------------------------------------------*/7 y, [, c+ A. ]7 l' `* n' S #include "stm32f10x_lib.h"1 r+ p: R# `! g5 y, } M2 j #include "stdio.h", V# L1 K# T- H2 b /* Private typedef -----------------------------------------------------------*/( l; W. j7 C$ ~ /* Private define ------------------------------------------------------------*/ #define USART1_DR_Base 0x40013804 /* Private macro -------------------------------------------------------------*/0 ^$ B% Z# x# i3 j+ C. y /* Private variables ---------------------------------------------------------*/) G3 p9 E, W! p+ N$ X m* o) m8 B #define SENDBUFF_SIZE 10240$ X) J5 H; u; f1 p3 J vu8 SendBuff[SENDBUFF_SIZE];, o& E' n: _, I+ n( R vu8 RecvBuff[10];" s2 y) K' n, b: [! M vu8 recv_ptr;# A8 p) U l$ k- q- A( j: t /* Private function prototypes -----------------------------------------------*/- a( y( j% H4 | void RCC_Configuration(void); u% P2 r0 @; Z! ~2 p void GPIO_Configuration(void); void NVIC_Configuration(void); void DMA_Configuration(void);, Y, b9 t( D5 L9 }! Y. r void USART1_Configuration(void);+ W4 M9 ?: N- | int fputc(int ch, FILE *f); void Delay(void); /* Private functions ---------------------------------------------------------*/ /******************************************************************************* X& D0 _0 x% m- D2 r* N * Function Name : main. }& y( T9 a u2 b4 x. C3 { * Description : Main program./ @) k* g+ O, M5 |0 j5 x * Input : None* s# R4 z# s! ]" P7 y o; k5 ] * Output : None * Return : None, Y* H) u) A& C- r! V1 d *******************************************************************************/; q" r4 H J7 F3 ?/ ?3 V. Q int main(void) { u16 i;1 ?6 l" k n% { X. [ #ifdef DEBUG debug(); #endif5 Y, c- X8 o3 x$ c recv_ptr = 0; RCC_Configuration();9 n5 P- d% R' |; j8 m/ z; t GPIO_Configuration();7 w3 m A& X; \ NVIC_Configuration();5 \5 W* e& q6 c2 g DMA_Configuration(); USART1_Configuration();2 h2 _+ F9 _4 ^( a8 C5 K printf("\r\nSystem Start...\r\n"); printf("Initialling SendBuff... \r\n");" p6 B. A1 `, L! s; L: k for(i=0;i<SENDBUFF_SIZE;i++)6 e" u( A# U% q' ?8 u4 R { SendBuff = i&0xff;3 q7 g w+ p" O+ v/ k6 p } printf("Initial success!\r\nWaiting for transmission...\r\n");# n5 W8 B7 U7 z9 L9 F& [ //发送去数据已经准备好,按下按键即开始传输2 b* `. A, G& e+ G7 H# R" S* g while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3)); printf("Start DMA transmission!\r\n"); //这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);' A: b: n: d4 { //开始一次DMA传输! DMA_Cmd(DMA1_Channel4, ENABLE);( `4 Z" j1 }& Q4 k0 @8 \ //等待DMA传输完成,此时我们来做另外一些事,点灯 //实际应用中,传输数据期间,可以执行另外的任务1 f' F9 L8 ^% |, D' k0 H9 w4 d while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) { LED_1_REV; //LED翻转. P3 V% c B6 F Delay(); //浪费时间 } //DMA传输结束后,自动关闭了DMA通道,而无需手动关闭 //下面的语句被注释 //DMA_Cmd(DMA1_Channel4, DISABLE);5 e: n, m/ G ~* ]7 b- L. B8 Y printf("\r\nDMA transmission successful!\r\n"); /* Infinite loop */" A2 j& e, c! x7 H; U" V. u+ t while (1)# o" K8 o; I3 v' ~* h9 M) [" X { }; v( I! Z6 w3 A/ k$ } } /******************************************************************************* * Function Name : 重定义系统putchar函数int fputc(int ch, FILE *f) * Description : 串口发一个字节1 r* e1 k2 E- q& w/ D% l * Input : int ch, FILE *f7 }. f( H0 J4 M! x, {, M * Output : * Return : int ch * 这个是使用printf的关键! t. L6 V. Y) v7 U *******************************************************************************/$ |1 ^9 U) D9 S B int fputc(int ch, FILE *f) {3 q- v8 P3 d% r% t2 B% q$ q //USART_SendData(USART1, (u8) ch);, b; R2 G( _) P USART1->DR = (u8) ch;4 Z+ `6 C7 G# z1 ~ `; q /* Loop until the end of transmission */; r" z6 N+ q! O2 v while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)( u% {( O2 I& k, e { }! ?9 r4 Q' ]1 Z9 C; m return ch; } /******************************************************************************* * Function Name : Delay * Description : 延时函数 * Input : None * Output : None * Return : None8 R" f# e" l% ]' U2 }! j *******************************************************************************/% ?2 m/ l$ ?/ ~8 B void Delay(void)8 p7 q2 t J( \3 Z3 z, l {( `' C$ j# q& b u32 i; for(i=0;i<0xF0000;i++);1 _" V( z! w% [/ G8 D) \ return; } E- S" @4 G, X8 v: n6 v /******************************************************************************* * Function Name : RCC_Configuration * Description : 系统时钟设置 * Input : None( B3 B) x, X! M/ V1 v8 m8 l * Output : None * Return : None *******************************************************************************/6 X) u8 U; C4 m. j" l$ F void RCC_Configuration(void) {) w) T( v5 B8 C( d+ R* ~% o ErrorStatus HSEStartUpStatus;$ T" \* K" }: \0 Q; ^1 t: J //使能外部晶振 RCC_HSEConfig(RCC_HSE_ON);- n( q7 h, B$ r //等待外部晶振稳定9 Z0 x; |7 _* d6 n; ] HSEStartUpStatus = RCC_WaitForHSEStartUp(); //如果外部晶振启动成功,则进行下一步操作 if(HSEStartUpStatus==SUCCESS)" R: V" k" b( V1 e, d {5 B2 e7 r6 t) t0 j- s //设置HCLK(AHB时钟)=SYSCLK RCC_HCLKConfig(RCC_SYSCLK_Div1); //PCLK1(APB1) = HCLK/2" `7 a: z# I' ^( Q7 i% S2 k) ]% P* _ RCC_PCLK1Config(RCC_HCLK_Div2);) h( H! b6 _' x* i& b //PCLK2(APB2) = HCLK2 e, {, O9 h" O$ \7 ]3 z8 i RCC_PCLK2Config(RCC_HCLK_Div1); //FLASH时序控制5 I5 e1 S0 i d" A% `6 O& N0 t4 l //推荐值:SYSCLK = 0~24MHz Latency=0 // SYSCLK = 24~48MHz Latency=1( K3 M/ y. l0 F2 r0 E // SYSCLK = 48~72MHz Latency=29 f! @ m4 P; ^1 r) ^) v 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);9 E) ]* g( q& E3 i1 V //启动PLL! j. _& K& ~2 O. m RCC_PLLCmd(ENABLE); //等待PLL稳定) G" T& t! j+ l& i while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //系统时钟SYSCLK来自PLL输出 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //切换时钟后等待系统时钟稳定 while(RCC_GetSYSCLKSource()!=0x08); /* o$ V' h: U% u8 d //设置系统SYSCLK时钟为HSE输入- D9 B, ]4 Z7 R- e* s% z RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);% f3 A7 ^+ L4 s B/ u, R5 M& D //等待时钟切换成功* p+ T w7 Y+ P while(RCC_GetSYSCLKSource() != 0x04);; [( ~: P# t- ?4 P" m3 d+ ` */" M) w0 X9 U# V4 C+ _ }5 D* _7 h) j+ w. L' Z' g5 l //下面是给各模块开启时钟 //启动GPIO( t7 d- t% f& m4 A4 M$ D2 |5 Q/ r" T RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \ RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\ ENABLE);3 r2 f) S9 T1 S( W2 G; I% P //启动AFIO RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);! Y2 I+ ]' z o/ R& J7 i) G //启动USART1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);8 o' Q: j3 j; p; x5 _ //启动DMA时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); }4 |) X6 v& u& U+ q1 Q3 u /*******************************************************************************6 {$ o2 q! S; \* j+ R( u; O * Function Name : GPIO_Configuration * Description : GPIO设置1 a- O( U! I9 E2 r1 K6 q * Input : None * Output : None' D' C6 G, ?! F7 p9 U' N * Return : None *******************************************************************************/8 v7 E0 W' i' O9 g! W void GPIO_Configuration(void) {; H$ q+ y7 z: |# V# ~/ j. t3 K: h& \ GPIO_InitTypeDef GPIO_InitStructure;" A0 |( a2 x3 g9 `$ m$ C" ~: g //PC口4567脚设置GPIO输出,推挽 2M+ S% n: j& D+ G7 b" T' i GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;% g z% T9 y/ n. N1 i GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;( C2 r3 e% G9 j p1 }2 C GPIO_Init(GPIOC, &GPIO_InitStructure); //KEY2 KEY3 JOYKEY0 z! I) D% M$ { //位于PD口的3 4 11-15脚,使能设置为输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\! M# h% [% z: {! q/ P GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure); //USART1_TX' {, {9 E" ]% a1 T: w2 `- o2 V GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;' @+ d, a% Q& E; o0 f# W/ \/ U GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;6 N2 C% u5 h$ ]3 D7 k4 ? GPIO_Init(GPIOA, &GPIO_InitStructure);% H0 X: c3 V# _! o& Y //USART1_RX0 w2 t- s0 V A* z( H2 m GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure);) d5 H9 {! }. z' v5 J! E } /******************************************************************************* * Function Name : NVIC_Configuration% Z/ B7 M D- g4 r! i' C. } * Description : NVIC设置 * Input : None * Output : None * Return : None *******************************************************************************/; I2 T9 P$ ?1 t" V* |3 I) Q void NVIC_Configuration(void) {: A7 }1 F' L* r1 Q+ F x) N f NVIC_InitTypeDef NVIC_InitStructure;: U$ A) T0 t- F( c #ifdef VECT_TAB_RAM // Set the Vector Table base location at 0x20000000 NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */# @1 Z! b# j# W, p; v // Set the Vector Table base location at 0x080000007 G8 e7 L6 O0 B) G8 x1 ?- H NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级) F- m7 I$ k4 X( M( g NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);3 N! W, e$ h6 n- ^, r$ b //串口接收中断打开 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);: u$ i: u6 a& W( W3 Z } /******************************************************************************* * Function Name : USART1_Configuration7 U x Z' Q- v# T- G% b * Description : NUSART1设置. t- O" R+ V3 L6 e * Input : None * Output : None. o0 `( H% D! c * Return : None/ Z5 Y5 f1 [2 Z) D# ~ *******************************************************************************/$ [% b+ l! U. ^2 O0 V: t: q void USART1_Configuration(void) { USART_InitTypeDef USART_InitStructure;9 p4 [% X! r! Y0 G9 o USART_InitStructure.USART_BaudRate = 9600;' Y4 Q, \+ q f2 |0 Q5 r USART_InitStructure.USART_WordLength = USART_WordLength_8b;1 z: a2 p( T+ L USART_InitStructure.USART_StopBits = USART_StopBits_1;9 y/ W# {9 V1 C' u) b( m5 M USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;+ A( R4 {! p( d/ X USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure);8 ^+ \* p y# D5 H5 O' ^( U USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);5 B8 J2 Y3 e5 v# q" f( E0 N USART_Cmd(USART1, ENABLE);% D! Z1 n4 A" ]! O }1 ?, l4 E6 V5 P8 g' h3 \ void DMA_Configuration(void)1 U8 f. O9 m. @ { DMA_InitTypeDef DMA_InitStructure;5 E3 j* ]( V- [( n5 F* I //DMA设置: //设置DMA源:内存地址&串口数据寄存器地址2 {2 p, {" d" P4 {! o //方向:内存-->外设 //每次传输位:8bit# J& k+ C# y1 X. m- }* Y //传输大小DMA_BufferSize=SENDBUFF_SIZE //地址自增模式:外设地址不增,内存地址自增1 //DMA模式:一次传输,非循环6 X) L, f; \ k1 { //优先级:中. @" \7 v- A' T1 V DMA_DeInit(DMA1_Channel4);9 w& I9 Z8 D2 V2 w: Y; w; K DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;# Y7 _% s/ Y" S# Q" T' g DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;. S$ e6 |& n+ l9 Z DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 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;) `1 C8 L7 y B/ j& U& B DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel4, &DMA_InitStructure);. Z7 a) i6 u: D# U% o } |
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不够用经验分享