Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30104100
  • 博文数量: 230
  • 博客积分: 2868
  • 博客等级: 少校
  • 技术积分: 2223
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-08 21:48
个人简介

Live & Learn

文章分类

全部博文(230)

文章存档

2022年(2)

2019年(5)

2018年(15)

2017年(42)

2016年(24)

2015年(13)

2014年(1)

2012年(5)

2011年(58)

2010年(56)

2009年(9)

我的朋友

分类: 嵌入式

2010-10-06 23:11:29

第一节: 陌生的她和大叔
       人近中年,不知不觉竟然成为孩子的父亲,不知不觉竟然成为别人的大叔,心中很是彷徨,我已不再年少。前些日子学习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->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<


   NVIC->ISER[1] |= 0X10;//开spi2中断

   SPI_X.SPI_Mode = SPI_Mode_Master;

   SPI_Init(SPI1,&SPI_X); //spi1为主

   SPI1->CR2 |= (1<
   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;; //清楚标志



}

 }

}

阅读(3114) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~