STMCU小助手
发布时间:2022-1-18 19:42
|
/****************************************************************************** * 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()( V/ }- \- N9 i5 T5 D; J * 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输9 z- W% j6 D; I+ F$ L5 @- Z * 每当USART的发送缓冲区空时,USART模块产生一个DMA事件, * 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART * 整个过程无需用户程序干预,用户只需启动DMA传输传输即可 * 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止 * 串口依然发送,表明DMA传输是一个独立的过程。 * 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理 * 作者:jjldc(九九) * 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6" N: l, I( z% c d5 F6 U *******************************************************************************/* B2 ?# d3 h7 _! w /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_lib.h" #include "stdio.h" /* Private typedef -----------------------------------------------------------*/) r3 W4 Z9 E4 J# r3 D /* Private define ------------------------------------------------------------*/0 J W+ }, ?' r; t/ a9 \- c #define USART1_DR_Base 0x40013804! I3 E3 H1 e8 V /* Private macro -------------------------------------------------------------*/2 l# V2 ?' }& h. X. P /* Private variables ---------------------------------------------------------*/ #define SENDBUFF_SIZE 10240 vu8 SendBuff[SENDBUFF_SIZE]; vu8 RecvBuff[10];$ _& y: l) I- R# u vu8 recv_ptr;* }3 y% s* i2 x" d+ c& i' q1 k /* Private function prototypes -----------------------------------------------*/, A! N V* u+ q+ Z9 d( k1 i* ]: b void RCC_Configuration(void); void GPIO_Configuration(void);0 k$ i1 `/ i7 L) p4 f# ]; _5 v void NVIC_Configuration(void);3 C) B! ` h6 L/ U( X; ^' v void DMA_Configuration(void); void USART1_Configuration(void); int fputc(int ch, FILE *f); void Delay(void); /* Private functions ---------------------------------------------------------*/ /******************************************************************************* * Function Name : main+ }4 A( W* b: g4 b: _+ D+ O * Description : Main program.0 Y+ e6 e) n9 [& A6 [; \ * Input : None( D8 g! ]3 ^# ]! D- q * Output : None; C9 E7 ^4 d G3 A0 _- ?# v$ s * Return : None( T4 a, _7 g( Q% {9 o) M! v- f *******************************************************************************/" ?7 {! v* K& Q% g2 p' x int main(void) { u16 i; #ifdef DEBUG- {1 d; p, p5 _- o" Q) t debug(); #endif recv_ptr = 0;3 x4 r( l% i* h+ g( m; J" @ RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration();0 h. Q3 n' S# D2 h DMA_Configuration();% H5 [: }/ W" v; B USART1_Configuration(); printf("\r\nSystem Start...\r\n"); printf("Initialling SendBuff... \r\n");/ c& c+ x G1 \" }( `- A for(i=0;i<SENDBUFF_SIZE;i++)& @$ r9 E& |+ K! a* z5 | {, x& _7 P5 ]: i! {: [, Z( f% j SendBuff = i&0xff;% J4 u. c* n0 e! [2 L } 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方式工作4 t9 k( a' `% A% f) ]2 O& U USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //开始一次DMA传输! DMA_Cmd(DMA1_Channel4, ENABLE); //等待DMA传输完成,此时我们来做另外一些事,点灯9 K9 }4 J; }0 E9 F //实际应用中,传输数据期间,可以执行另外的任务 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)* t- D, x1 I4 ~5 Z- m {" g! J2 U2 r8 @, B4 a9 L# g LED_1_REV; //LED翻转9 U8 v4 @3 C. o, ^' q Delay(); //浪费时间 }6 S+ r2 i0 x; K6 }* b! {2 d //DMA传输结束后,自动关闭了DMA通道,而无需手动关闭" |6 z% X) H) x: T1 @ //下面的语句被注释' l5 F9 H5 ~. ] //DMA_Cmd(DMA1_Channel4, DISABLE); printf("\r\nDMA transmission successful!\r\n");* o9 W! B' S4 x+ W; H9 x0 G* N' F8 {2 ] /* Infinite loop */ while (1) { } }% u: J6 x5 L) N7 o /*******************************************************************************4 M6 H, u+ ^7 L7 }4 C0 e * Function Name : 重定义系统putchar函数int fputc(int ch, FILE *f)( A* q$ e4 v& c * Description : 串口发一个字节 * Input : int ch, FILE *f0 T% c& I; F- l1 f2 i7 s, J% O * Output : S- P" _4 C1 f$ I * Return : int ch9 R5 R# e5 K5 h' ~- t2 N3 w * 这个是使用printf的关键 *******************************************************************************/ int fputc(int ch, FILE *f)1 K8 _! t8 M+ `& I1 K6 l* u { //USART_SendData(USART1, (u8) ch); USART1->DR = (u8) ch; /* Loop until the end of transmission */ while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)/ b& u- J" ]' S( k d* a { } return ch; } /******************************************************************************* * Function Name : Delay * Description : 延时函数 * Input : None * Output : None2 ^( B" p8 T" C0 k; p' R W * Return : None8 @9 h2 S( ~# X; ~* l0 X/ k0 G- G *******************************************************************************/ void Delay(void). @$ f" a& j+ B! h { u32 i; for(i=0;i<0xF0000;i++); return;# c, p ^# j) c. S# l. O. |; G& t2 C }: ^' }1 ?) M6 o1 d. K* [ ` /******************************************************************************* * Function Name : RCC_Configuration I9 l) A6 h4 B, K * Description : 系统时钟设置 * Input : None9 f5 g" t8 ~1 I+ l8 C: \. r * Output : None" R. {: N! G) Y' f * Return : None *******************************************************************************/- S, K* g5 D f) l void RCC_Configuration(void) { ErrorStatus HSEStartUpStatus; //使能外部晶振) e6 T. t. p. A0 i9 v RCC_HSEConfig(RCC_HSE_ON);0 C, H! t3 n: j* s# t* s6 i4 L //等待外部晶振稳定 HSEStartUpStatus = RCC_WaitForHSEStartUp();- ~' P. E, I! X& u //如果外部晶振启动成功,则进行下一步操作/ v0 }+ k8 E9 }. F" a if(HSEStartUpStatus==SUCCESS) {* {( z* G4 z) O6 s# G% \ //设置HCLK(AHB时钟)=SYSCLK/ w2 T" I; k% P/ y; g RCC_HCLKConfig(RCC_SYSCLK_Div1);3 ~4 ^9 f) n! o* v/ T- T //PCLK1(APB1) = HCLK/28 E3 c& z2 ?. G' U RCC_PCLK1Config(RCC_HCLK_Div2);/ @3 ^6 Z; | n/ M1 X3 G. o+ [& \* _ //PCLK2(APB2) = HCLK# i! n8 v. C A) O4 p) B2 c; { RCC_PCLK2Config(RCC_HCLK_Div1); //FLASH时序控制 //推荐值:SYSCLK = 0~24MHz Latency=0' t* `: t# E6 B" T3 \ // SYSCLK = 24~48MHz Latency=1 // SYSCLK = 48~72MHz Latency=20 |0 a" P' _6 i( p8 u, Z$ T 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); //启动PLL RCC_PLLCmd(ENABLE); //等待PLL稳定& t0 S3 X- |0 l7 x" a! K while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);$ ^* T2 G' f# }$ y) L6 ~' X //系统时钟SYSCLK来自PLL输出3 F5 r+ G, g; D2 m RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //切换时钟后等待系统时钟稳定 while(RCC_GetSYSCLKSource()!=0x08); /*9 @, \( X ^) s V+ w% t, N6 h( G# M- P //设置系统SYSCLK时钟为HSE输入. y6 a4 f3 ?( F E2 l RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); //等待时钟切换成功3 d+ C F0 Q$ p# u9 ] while(RCC_GetSYSCLKSource() != 0x04); */3 X$ E) |* F# R4 A( ]) y5 T }1 y( ^7 R2 \3 w. w0 w6 C" a //下面是给各模块开启时钟/ I+ W+ t' ?8 Q5 a //启动GPIO7 m7 H0 k+ c ~3 l RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \ RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\ ENABLE); //启动AFIO/ l0 [' M. L3 z RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);1 n3 S- a3 o" _( l2 V" F* }# A //启动USART1, Q" q4 v1 W7 o; W! O* _0 p- t/ O RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //启动DMA时钟: `% i! Z- S( {0 x RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); }+ G& S6 m/ X1 u e% |* D) L: s /******************************************************************************* * Function Name : GPIO_Configuration% _2 F1 r* p$ F$ p; S& q+ q. F * Description : GPIO设置' I4 l1 r/ v$ w2 z) L * Input : None, L$ }& N3 h( R. t+ N3 [% Q3 | * Output : None# `% C4 i/ Y& T6 v0 u. [2 @5 A * Return : None *******************************************************************************/ void GPIO_Configuration(void)' x2 @, M. K' l" p) p { GPIO_InitTypeDef GPIO_InitStructure;* J7 R+ x+ Z% Z8 Z //PC口4567脚设置GPIO输出,推挽 2M/ y! G: s1 u, l3 k' _ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;4 w2 \) Z" [, ^! P6 l/ N. ] GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); //KEY2 KEY3 JOYKEY //位于PD口的3 4 11-15脚,使能设置为输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11 | GPIO_Pin_12 |\ GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;- N; {) t( U: e& z2 p& Y. |6 f. q GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;% u0 j5 B: v7 m3 @ v GPIO_Init(GPIOD, &GPIO_InitStructure);# z2 Y. @+ p) I$ E! D- c6 N //USART1_TX" x. d( G0 k; R6 n) b. R* U' n GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;& h. W8 A* N* J$ J: n/ i GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;* H* V9 `6 \1 @: \# A GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;0 ~/ \ s0 q: S5 b, M9 u, W2 K GPIO_Init(GPIOA, &GPIO_InitStructure); } /*******************************************************************************& g7 ?8 N0 _* T1 u3 k4 x" X" n * Function Name : NVIC_Configuration * Description : NVIC设置 * Input : None0 c: e& H5 S; x6 }+ k- H * Output : None+ h2 j) F9 Z& l6 W0 Q2 C0 k/ s! x0 ^ * Return : None! | B* b6 v( O, z *******************************************************************************/ void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; #ifdef VECT_TAB_RAM // Set the Vector Table base location at 0x20000000$ d* o) y, H. \- ?! T9 ^' B- y2 } NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);. a3 ^+ ~* K% ~ #else /* VECT_TAB_FLASH */ // Set the Vector Table base location at 0x08000000 NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);$ z, X: i% j7 ^$ ]1 j. B6 V+ @, n #endif //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //串口接收中断打开 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;2 |' X6 v/ B. T$ ]- D% B1 D NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;( k4 ?+ }2 ?( S9 O3 b3 s1 C NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;- j; Y: a) S7 T0 F7 v7 _ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);% ?# k8 P s0 X2 B1 Y+ n. N- ^ } /*******************************************************************************/ }' |, Z8 d/ v) M% r+ j* L * Function Name : USART1_Configuration" c* X1 M) J% ?! M * Description : NUSART1设置 * Input : None6 z' h! Q5 C" k& K& c6 { * Output : None3 C: z9 S3 i2 u7 f- [3 I * Return : None *******************************************************************************/ void USART1_Configuration(void) {; H: u- e3 p @! F USART_InitTypeDef USART_InitStructure;8 U, u% N. U0 j% }: s& \ USART_InitStructure.USART_BaudRate = 9600;& T1 c8 G; x7 G, O; i USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1;1 t9 a/ H0 \) U/ r) W2 z USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;0 J/ o& V$ k6 n# J$ w USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); } void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure;6 g$ n- R# Q& V5 N( k* X4 R2 }) H //DMA设置: //设置DMA源:内存地址&串口数据寄存器地址) N& _5 L+ m) l% o //方向:内存-->外设6 e$ [5 X$ a6 t //每次传输位:8bit$ c+ a6 R6 I$ f! n) c) g //传输大小DMA_BufferSize=SENDBUFF_SIZE //地址自增模式:外设地址不增,内存地址自增13 g6 j- I& ?+ Q% ^- \+ s) j //DMA模式:一次传输,非循环! q4 y$ e2 U* m) U: j) _ //优先级:中 DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;9 I5 \# \* H& E7 Z& X- j- P DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;. f0 b2 w1 N! [/ W- E ^ DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/ o6 p! K" f! g( [. \ 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;- Y- W$ F/ d d7 Y1 ~6 n DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;1 ~! \/ V6 a' Y8 W5 G; \+ d5 E& f DMA_Init(DMA1_Channel4, &DMA_InitStructure); }0 b3 Y; m, I7 Z5 u# \$ D |
实战经验 | 基于STM32G0B1的全桥移相+同步整流PWM解决方案
DMA 原理从 0 到 1:为什么它能解放 CPU?一文讲透 DMA 的工作流程
【福利三:逢7发帖赢大礼】8、基于STM32G070板子的Ymodem串口协议IAP Bootloader开发
【福利三:逢7发帖赢大礼】7、基于STM32G070板子TF卡的FATFS移植
【福利三:逢7发帖赢大礼】6、基于STM32G070板子spiflash的FATFS移植
【福利三:逢7发帖赢大礼】5、基于STM32G070板子IRDA红外遥控接收解码
【福利三:逢7发帖赢大礼】4、基于STM32G070板子SPI flash 移植SFUD库
【福利三:逢7发帖赢大礼】基于STM32G070板子的uart shell移植设计
【福利三:逢7发帖赢大礼】3、基于STM32G070板子的YModem串口协议通信
【福利三:逢7发帖赢大礼】2、基于STM32G070板子的OLED移植U8G2库
微信公众号
手机版