原创 stm32使用心得

2010-11-5 12:00 3567 9 10 分类: MCU/ 嵌入式

stm32使用心得


       第一次使用stm32,以前用过51、avr、pic、2812,感觉stm32还真有点不一样,呵呵。


因为是第一次使用,下面说的肯定有不少错误,诚心求大家指正。


       这次做的是用stm32f103zd+lattice 的lc4256v做一个波形发生器。通过上位机可以控制生成波形的频率,然后stm32根据频率计算波形占空比数据,通过总线形式传给cpld,然后cpld把这些数据转换成相对应占空比的pwm输出,外部接RC滤波电路,产生相对应的波形。由于频率范围较大,计算量也比较大,所以采用了stm32+cpld的结构。Stm32运行在72MHZ,通过mco脚给cpld 36M HZ的时钟,stm32和cpld通过总线方式通信。


       此系统中Stm32主要用到的资源是:一个UART,一个TIMER及其中断,FSMC和DMA。


       本人总结了下,Stm32初始化一个片内外设一般过程一般有以下几部分:


1.  InitStructure配置及初始化


2.  时钟使能


3.  相对应的IOInitStructure配置及初始化


4.  相对应的IO时钟使能


5.  外设使能


6.  中断配置及中断程序编写


下面介绍一下自己所用的UART、TIMER、FSMC、DMA的初始化。


UART初始化:


       此系统中使用的是UART2,未用UART中断。UART初始化主要有:IO初始化,UART InitSturcture初始化,UART时钟使能,UART使能。程序如下:


GPIO_InitTypeDef GPIO_InitStructure;


// Configure USART2_Tx as alternate push-pull


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;


    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;


    GPIO_Init(GPIOA, &GPIO_InitStructure);


 


    // Configure USART2_Rx as input floating


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;


    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;


GPIO_Init(GPIOA, &GPIO_InitStructure);


//IO时钟使能


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);


USART_InitTypeDef USART_InitStructure;


  /* USART2 configured as follow:


        - BaudRate = 9600 baud 


        - Word Length = 8 Bits


        - One Stop Bit


        - No parity


        - Hardware flow control disabled (RTS and CTS signals)


        - Receive and transmit enabled


  */


  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;


  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;


 


  /* Configure the USART2*/


  USART_Init(USART2, &USART_InitStructure); 


//UART时钟使能 


RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);


  /* Enable the USART2 */


  USART_Cmd(USART2, ENABLE);


TIMER初始化


       使用的是TIM2。初始化主要包括TIM2 InitSturcture初始化,时钟使能,TIM2开启,中断配置,及中断服务程序编写。此TIM2作用主要是给DMA提供时钟,DMA在TIM2 UP时启动一次DMA发送过程。TIM2程序如下:


       TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;


       //定时器2


  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);


  TIM_TimeBaseStructure.TIM_Period = 33;


  TIM_TimeBaseStructure.TIM_Prescaler = 71;


  TIM_TimeBaseStructure.TIM_ClockDivision = 0;


  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;


  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;


  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);


  TIM_ClearFlag(TIM2,TIM_FLAG_Update);


  TIM_ARRPreloadConfig(TIM2,ENABLE);


  TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);


  TIM_Cmd(TIM2, ENABLE);


//中断配置


/* Enable the TIM2 gloabal Interrupt */


  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;


  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;


  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;


  NVIC_Init(&NVIC_InitStructure);


//定时器2中断服务程序


void TIM2_IRQHandler(void)


{


  TIM_ClearITPendingBit(TIM2,TIM_IT_Update);


}


FSMC初始化


       FSMC主要用来和CPLD进行总线通信,由DMA方式发送,在TIM2计时时间到后启动一次DMA发送,发送的数据由已计算好的数组中的一个16位数据以16位方式发给FSMC的地址。由于此系统电路已固定,stm32与CPLD间数据线是8位,故在向FSMC地址写16位数据时,FSMC会将数据拆成2部分发送。本人在实际编程时发现,如向*(volatile u16*)(Bank1_NOR4_ADDR+0x40)地址给CPLD写16位数据时,会在40h接收到低8位数据,在41h接收到高8位数据。按道理来说这些数据应该与NBL0, NBL1信号有关,本人在CPLD编程时未理会这个,具体时序不是很清楚,有待考究。


       FSMC初始化程序如下:


FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;


       FSMC_NORSRAMTimingInitTypeDef  p;


       p.FSMC_AddressSetupTime = 3;  //6


       p.FSMC_AddressHoldTime = 0;     //3


       p.FSMC_DataSetupTime = 8;  //25


       p.FSMC_BusTurnAroundDuration = 0;


       p.FSMC_CLKDivision = 0;


       p.FSMC_DataLatency = 0;


       p.FSMC_AccessMode = FSMC_AccessMode_A;


      


       FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;


       FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;


       FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;


       FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;


       FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;


       FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;


       FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;


       FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;


       FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;


       FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;


       FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;


       FSMC_NORSRAMInitStructure.FSMC_AsyncWait = FSMC_AsyncWait_Disable;


       FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;


       FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;


       FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;


      


       FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); 


       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);


       FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);


//IO初始化


GPIO_InitTypeDef GPIO_InitStructure;


 


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOG | RCC_APB2Periph_GPIOE |


                         RCC_APB2Periph_GPIOF, ENABLE);


 


/*-- GPIO Configuration ------------------------------------------------------*/


  /* SRAM Data lines configuration */


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 |


                                GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;


  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;


  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


  GPIO_Init(GPIOD, &GPIO_InitStructure);


 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |


                                GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |


                                GPIO_Pin_15;


  GPIO_Init(GPIOE, &GPIO_InitStructure);


 


  /* SRAM Address lines configuration */


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |


                                GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13 |


                                GPIO_Pin_14 | GPIO_Pin_15;


  GPIO_Init(GPIOF, &GPIO_InitStructure);


 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |


                                GPIO_Pin_4 | GPIO_Pin_5;


  GPIO_Init(GPIOG, &GPIO_InitStructure);


 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;


  GPIO_Init(GPIOD, &GPIO_InitStructure);


  


  /* NOE and NWE configuration */ 


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5;


  GPIO_Init(GPIOD, &GPIO_InitStructure);


 


  /* NE4 configuration */


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;


  GPIO_Init(GPIOG, &GPIO_InitStructure);


 


  /* NBL0, NBL1 configuration */


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;


  GPIO_Init(GPIOE, &GPIO_InitStructure);


此处简单介绍一下FSMC总线方式的使用。


       FSMC初始化完了之后,进行如下定义,


#define Bank1_NOR4_ADDR       ((u32)0x6c000000)


#define cs_sin  *(volatile u16*)(Bank1_NOR4_ADDR+0x40)


然后cs_sin=1000就是往这个地址写数字1000=0x03e8,则cpld 40h地址收到数据为0xe8,41h收到的数据为0x03


i=cs_sin,就是读这个地址的数据,由于定义的是16位的数据地址,故读到的数据是40h为低8位数据,41h为高8位数据


DMA初始化:


       DMA在TIM2 UP时触发,将已经计算好放在数组dat_tocpld的16位数据发送到fsmc地址为(Bank1_NOR4_ADDR+0x40)的空间。


       初始化程序如下:


DMA_InitTypeDef DMA_InitStructure;


  DMA_DeInit(DMA1_Channel2);


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


  /* Enable TIM2 DMA interface */


  TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);


 


  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(Bank1_NOR4_ADDR+0x40);


  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)dat_tocpld;


  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;


  DMA_InitStructure.DMA_BufferSize = 1152;


  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;


  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;


  DMA_InitStructure.DMA_PeripheralDataSize =  DMA_PeripheralDataSize_HalfWord;


  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;


  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;


  DMA_InitStructure.DMA_Priority = DMA_Priority_High;


  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;


  DMA_Init(DMA1_Channel2, &DMA_InitStructure);


  /* Enable DMA1 Channel2 */


DMA_Cmd(DMA1_Channel2, ENABLE);


  最后附上源自http://sxqstudy.blog.163.com/blog/static/34562512009625103148709/介绍的关于PWM电压转换电路。


 


在PWM用于DA转换的场合,阻容滤波电路是关系转换效果的重要环节。


由RC充放电常数我们可以大致计算出阻容环节的充放电频率,一般为了得到理想的滤波效果,这个频率要远小于PWM的输出频率(小于四分之一)。


一般情况下,当C较小R较大时,DA转换出的电压损耗很小,但是纹波却很大;当C较大R较小时,DA转换出的电压损耗很大,但纹波相对较小。


所以当需要进行线形度很高的精确DA转换时必须使用较小的滤波电容,且尽量避免使用电解类电容。而为了得到较强的信号输出,RC惯性环节之后还必须加一级高性能的电压跟随,然后在跟随器输出的地方加上一个滤波用的电解电容,用于平滑RC惯性环节的纹波。但是这还不够,因为这时的输出电压里可能含有较多的交流谐波成分,如果处理不当,跟随器有可能自激。解决的办法就是使用一个小的去藕电容。而且这里电容的放置顺序必须是电解电容在前,去藕电容在后!


如果输出电压精度和线形度要求不高,但是对纹波要求却很高,或者这个电压比较固定时,可以使用电容较大的滤波组合。因为,虽然大电容的直流损耗较大,但是我们可以通过调节PWM占空比来达到要求的输出电压,或者通过一级AD转换的反馈来实现精确的固定电压输出。只是这里仍然要加一级电压跟随器,以便于后级采集电路使用,且AD采集点放置在跟随器输出处。

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户377235 2012-12-9 21:56

至今没有解决

用户377235 2012-11-29 21:15

我也遇到同样的问题,真是烦人! 不知你怎么解决的,我没在迷途!

用户1584993 2010-11-5 16:55

支持原创,支持分享学习笔记
相关推荐阅读
用户282447 2011-01-19 17:05
stm32使用fsmc时地址移位问题
stm32平台使用fsmc时,当操作数据宽度为8位时,HADDR【25:0】与FSMC【25:0】对齐,当操作的数据为16位时,HADDR【25:1】与FSMC【24:0】对齐,HADDR【0】未接。...
用户282447 2011-01-05 19:42
verilog分频
fpga程序里经常会遇见给一个50 MHZ的clk,然后产生一个可变频率的clk‘。尤其是在电机控制中,加减速需要便频率,而fpga中除法又比较耗资源。今天看到一个程序,觉得思想不错,整理如下。   ...
用户282447 2011-01-01 23:47
2011,回顾从前
毕业第一年。    2010很快过去了,大学生活也已经成了历史,貌似很近,又貌似很远。    2011已经来临,是时候该回顾回顾自己大学至今都在做什么了。俗话说,男的把电脑当游戏机,女的把电脑当影碟机...
用户282447 2010-12-24 11:33
sdram verilog程序
sdram芯片用的是hy57v641620hgt-7,fpga用的是EP1C6Q240C8,晶振是50M,经过PLL倍频至125M,系统clk时钟是125M,sdram时钟相移-3ns程序是根据特权的...
用户282447 2010-12-24 11:26
串口verilog程序
发一个自己写的串口程序,波特率115200,一位起始位,8个数据位,一个停止位接收采用8倍过采样。下面有4个module,uart是顶层模块,uart_rx是接收模块,uart_tx是发送模块,uar...
用户282447 2010-11-27 18:58
tft verilog驱动
       使用的TFT为群创7寸液晶屏AT070TN83,分辨率为800*480FPGA为ep1c6q240c8,晶振为50M       首先介绍一下TFT接口       1和2脚VLED,4...
我要评论
1
9
关闭 站长推荐上一条 /3 下一条