title
收藏本站
联系站长
关于本站
首页 信息发布 产品宣传 论坛交流 学习文章 技术人生 项目源码 技术资料 人才收录
 今天是: 2010年7月10日 星期 六
欢迎光临!单片机群号:25930265(新) 71062262 21829895 64584393 26583231(只限加一群)  
热门文章推荐


当前位置:首页>>>单片机学习文章>> stm32调试记
stm32调试记
作者:tamson给他留言 [转载] 字体:
发表于:
2009-11-17 17:15:42
第一节: 陌生的她和大叔 
       人近中年,不知不觉竟然成为孩子的父亲,不知不觉竟然成为别人的大叔,心中很是彷徨,我已不再年少。前些日子学习stm8,一口气工作近2个星期,当时精神饱满,心中很是得意,原来我也可以年轻。谁知放假去了次青岛和家人度假回来后竟然感冒了一个星期,哎,我还是老了。 
       写完stm8调试记后,就想践踏一下stm32,就像大叔和美女。。。因为只有美女才能让大叔觉得年轻,只有美女才能让大叔精力旺盛,stm32是我的美女吗?我不知道,我要接近她,我要驾驭她。 
     KEIL 的大名人尽皆知,51年代就大放异彩。说到这儿,不得不说一下那些为电子公益事业做出贡献的先行者们。甚是怀念那个年代,丁丁,老万,所长,午夜听风,龙啸九天等诸多大虾。他们推广keil,他们无私的奉献,就像现在的老key一样,知无不言,言无不尽。 
     我使用的环境: keil mdk 350            
 St 的 三合一板 
板子虽小,还是可以做很多事情的,白菜老弟做的板子据说很强势,已经预定,现在先解下渴,玩玩只有一个STM32F103C8T6的小家碧玉。 
Mdk350集成了st的st link,所以只要在OPTION FOR TARGET 的 DEBUG 和UTILITIES下选择st link debug就可以正确连接。库使用的是v2.01 
我要让她跑起来,我需要做什么? 
我要有一个时钟,目标是48mhz,这是为了以后调试usb 
STM32的时钟和STM8的时钟基本上是一样的。她内部有个8mhz的振荡器,不过我不打算用它。三合一板外部焊接了一个8mhz的晶振我要用她做时钟源。 
时钟初始化:   
             RCC_DeInit();  //恢复默认值这没什么用,不写他也不影响运行  
          RCC_HSEConfig(RCC_HSE_ON ); //启动外部时钟  
          while(!RCC_GetFlagStatus(RCC_FLAG_HSERDY));//等待外部时钟稳定  
          FLASH_SetLatency(FLASH_Latency_1); //48mhz运行时,flash要加一个等待周期 
       其实刚开始时我没有加这个延时,也没有什么不良的反应,不知道时间长了会不会有问题  
          FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//预缓冲使能  
          RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);//pll输出是外部时钟的6倍  
          RCC_PLLCmd(ENABLE); //使能pll  
          while(!RCC_GetFlagStatus(RCC_FLAG_PLLRDY));//等待pll稳定  
          RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//切换到PLL时钟  
          while(RCC_GetSYSCLKSource()!=0x8);//等待系统时钟稳定        
             RCC_PCLK1Config(RCC_HCLK_Div2);//低速时钟为24mhz  
          RCC_PCLK2Config(RCC_HCLK_Div1);//高速时钟为48mhz 
经过上面的设置,时钟正是工作,我们可以通过这个函数RCC_GetClocksFreq(); 
来验证 
      RCC_ClocksTypeDef  RCC_Clocks_T; 
      RCC_GetClocksFreq( &RCC_Clocks_T); 
RCC_Clocks_T中反应了sys clk,  HCLK  PCLK1,PCLK2, ADC CLK的频率。 
时钟有了,我们还要干点什么?板上有她唯一的外设,led小灯。我要让处于pb5的led亮。 
     //首先开启PB口的时钟,pb口在高速apb2上 
          RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE ); 
 下面要进行pb口的初始化  
          GPIO_InitTypeDef  GPIOB_STR;   //定义一个结构变量用于初始化                 
           GPIOB_STR.GPIO_Pin = GPIO_Pin_5;  //选择pb5  
            GPIOB_STR.GPIO_Speed = GPIO_Speed_10MHz; //最大10mhz输出  
            GPIOB_STR.GPIO_Mode  = GPIO_Mode_Out_PP;//推挽输出  
            GPIO_Init( GPIOB,&GPIOB_STR);  //配置pb5      
Pb5已经配置好了,下面我要点亮led,pb5要输出1 
        GPIO_SetBits( GPIOB,GPIO_Pin_5); 
相反熄灭她如下: 
        GPIO_ResetBits( GPIOB,GPIO_Pin_5);  
这一节就到这,意法的库真是好东西,stm8调试的时候没有使用是因为实在不愿看那么多的代码。现在学习stm32,顺便把她的库看了看,觉得虽然庞大琐碎,但结构很优美,便用了起来。不过我怕用习惯了,把我自己用傻了,以后换别的cpu时,不会用了。 
第二节 定时,中断,和意法的风骚       
         玩cpu吗当然等玩定时器,重要性在stm8一文中已有描述,这里不再多说。 
     我要使用tim2实现1s定时,这有些长不够实用,但是我只是玩玩。       
     第一步要配置时钟 
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_SPI2,ENABLE);  
      Tim2处于时钟树的apb1上。 
      下面是初始化代码 
                TIM2->PSC |=24000; //设置预分频,实现1ms  
           TIM2->ARR = 1000;  //1s产生一次中断  
           TIM2->DIER |=0X1;  //允许tim2更新中断  
           NVIC->ISER[0] |= (u32)(1<<TIM2_IRQChannel); //开tim2中断  
           TIM2->CR1 |=0X1;//启动tim2 
      说到这,不能不说意法的风骚,刚开始时翻遍手册也没看到nvic部分的说明,所以第一版本的tim2初始化没有nvic部分,以至不能进tim2的更新中断,后查阅阿莫的论坛才知有c_m3权威指南一物,实在让人无语。这是意法的风骚,这是新手的灾难。 
         每次新建工程时,keil会自动生成一个文件stm32f10x.s,在里面有中断向量表的描述。将相应的中断函数名实例化,就能实现中断入口。 
      我的tim2中断函数 
void TIM2_IRQHandler(void)//这个函数名能在stm32f10x.s中找到 

           static u8 flag; 
           if( flag ) 
           {              
               GPIO_SetBits( GPIOB,GPIO_Pin_5); //下面能实现上文说的led以0.5hz闪烁  
                     flag = FALSE;  
           } 
           else 
           {              
               GPIO_ResetBits( GPIOB,GPIO_Pin_5);   
                   flag = TRUE;              
           }        
           TIM2->SR &=0XFFFE;  //清楚更新标志 

上面没有用库函数,是因为我想自己的头脑里脉络更清楚,更复合我自己的风格。其实用库会简单 
第三节 SPI和懒懒的我 
       调试stm8时没有调spi实在是因为没有接口,在加上我这人懒散最终没有调它,如果是美女,我就不会这么客气了吧。 
       最近身体欠佳,总感觉力不从心。又觉得时间匆匆,再不加把力气真要荒废此生,便生出无奈。 
      闲话少说,说说spi吧。三合一板只有一个cpu,但它却有两个spi,我用飞线将他们互联,便形成了一个完整的spi通讯接口。 
Spi2处于时钟树的apb1,spi1处于时钟树的apb2,时钟部分已将apb1配置为24mhz 
Apb2为48mhz 
首先开启spi2和spi1时钟 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2\ 
                  |RCC_APB1Periph_SPI2,         \\这个是spi2的选项 
                  ENABLE); 
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB\ 
                                   |RCC_APB2Periph_SPI1\ //这个是spi1的选项 
                                  |RCC_APB2Periph_GPIOA\                                 
                                                          |RCC_APB2Periph_USART1,ENABLE                                   
                                                         ); 
下面是spi的初始化 
       u32 x;         
           u8 y;        
           SPI_InitTypeDef SPI_X;  
           SPI_X.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工  
           SPI_X.SPI_Mode = SPI_Mode_Slave;//式  
           SPI_X.SPI_DataSize = SPI_DataSize_8b;//  
           SPI_X.SPI_CPOL = SPI_CPOL_High;//时钟空闲是为高  
           SPI_X.SPI_CPHA = SPI_CPHA_2Edge;//  
           SPI_X.SPI_NSS  = SPI_NSS_Soft;//软件控制  
           SPI_X.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;  
             SPI_X.SPI_FirstBit = SPI_FirstBit_MSB;  
           SPI_Init(SPI2,&SPI_X);  
               SPI2->CR2 |= (1<<SPI_FLAG_RXENIE)|(1<<SPI_FLAG_TXENIE);//接受和发送 中断  
           NVIC->ISER[1] |= 0X10;//开spi2中断  
           SPI_X.SPI_Mode = SPI_Mode_Master;  
           SPI_Init(SPI1,&SPI_X); //spi1为主  
           SPI1->CR2 |= (1<<SPI_FLAG_RXENIE)|(1<<SPI_FLAG_TXENIE);  
           NVIC->ISER[1] |= 0X8;  
           SPI_Cmd(SPI2,ENABLE);  
           SPI_Cmd(SPI1,ENABLE);//使能spi1和spi2  
           SPI2->DR = 0Xaa;//发送数据 
中断处理函数 
void SPI1_IRQHandler( void ) 

      u16 x; 
          if( SPI1->SR &0X1)              
          {               
                 x = SPI1->DR;  
           }              
          if( SPI1->SR&0x2 )  
          {                
                  SPI1->DR =++test_data1;  
          } 

void SPI2_IRQHandler( void ) 

      vu16 x; 
          if( SPI2->SR &0X1)  
          {           
                 x = SPI2->DR;  
                 if( sam_data < SIZE_BUF ) 
                 {  
                    sam_data1[ sam_data++ ] =x;  
                 } 
                 else 
                 { 
                     sam_data = 0;       
                 } 
           }  
          if( SPI2->SR&0x2 )  
          { 
              SPI2->DR =++test_data; 
/*                  if(test_data1!=0) 
                  {              
                      test_data1 --;               
                  } 
                  else 
                  {             
                      test_data1 =10;  
                  }         */ 
          } 

外设使用的时候一定要先配置好io的使用模式。我就因为没有配置而吃了大亏。刚开始时收发怎么也不正常,后设置了io的方式才能工作。这大概是对新的事物还不熟悉。 
Io的模式无非是,出的数据流设成输出,入的数据流设成输入,什么可说。  
   关于spi的代码,不是好的风格,其中库夹杂着自己的方法,如果在严格的风格上这不叫方法,叫发疯。  
第四节:串口和新凤霞 
     最近听新凤霞的花为媒,让我有绕梁三日的感觉。喜欢的朋友可以听一下。老艺术家的东西越来越少了。时代在进步,我们在放弃。但放弃的都是优良的传统,如清廉,孝道,公正。 
     我手里有两个自己做的ch341转串口线缆,将小板的pa9(u1_TX,设置成推挽输出),和pa10(U1_RX,上拉输入) 
和ch341相连,就完成了硬件配置。 
     我要实现的功能,当cpu收到计算机发来的0XAA时,发送8个0X55,在上电时cpu主动发送一次8个0X55.  
     首先配置时钟, 
           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB\ 
                                     |RCC_APB2Periph_SPI1\ //这个是spi1的选项 
                                     |RCC_APB2Periph_GPIOA\                   
                                        |RCC_APB2Periph_USART1,ENABLE         //这个是串口项                 
                                                         ); 
下面是初始化: 
        USART_InitTypeDef uart_x;  
        NVIC_InitTypeDef nvic_x;  
        USART_Cmd(USART1,ENABLE); //使能串口  
        uart_x.USART_BaudRate = 19200;//19200, 8, n ,1  
        uart_x.USART_WordLength = USART_WordLength_8b;  
        uart_x.USART_StopBits = USART_StopBits_1;  
        uart_x.USART_Parity = USART_Parity_No;  
        uart_x.USART_Mode = USART_Mode_Rx |USART_Mode_Tx;//发送和接受  
        uart_x.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
        USART_Init(USART1,&uart_x);  
        USART_ITConfig(USART1,USART_IT_TC,ENABLE);//使能发送完成中断  
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能接受满中断  
        nvic_x.NVIC_IRQChannel = USART1_IRQChannel;//nvic的库开启方法  
        nvic_x.NVIC_IRQChannelCmd = ENABLE;  
        NVIC_Init(&nvic_x); 
中断函数 
void USART1_IRQHandler( void ) 

          vu16 x;            
          vu16 y ;  
          y = USART1->SR;//读状态 
         if(y & 0X20)//如果是非空中断 
         {   
                  x = USART1->DR&(u16)0xff;   
                // USART_SendData(USART1,0X55);  
                if( x == 0xaa ) 
                {                   
                   lentch_x = 0;  
                   USART1->CR1 |=(u16)0X8;//启动一次发送                   
                }  
         }    
         if(y & 0X40)//发送完成中断 
         {                 
                if(lentch_x < 8 ) 
                { 
                    USART1->DR = 0X55; 

                        lentch_x++; 
                } 
                else 
                { 
                         USART1->CR1 &=(u16)0XFFF7;; //清楚标志 
                } 
         } 

这次完全使用了库,哈。过两天使用dma试试,接下来还有adc等没有测试,可板子太小了可发挥的余地不多,就剩usb了,可是它太不好肯,得好好的准备准备,过阵子白菜的板子到了在研究。 
(本文引自www.mcujl.com/article.asp?conID=406)


---------------------------------------------------------------------------------------------------
[打印文章] [关闭本页] [返回顶部]
本网站部分资料转自网上,如有侵权请来信告明,我们会尽快删除  | 网站地图
Copyright @ 2007-2010 深圳单片机交流网.版权所有
网站创办者:詹长亮,周发辉,李林盛
网站支持:zcl843@163.com QQ:380476830 13723787271詹长亮