STM32----杂记

1、开启引脚复用,引脚外部中断时,需要开启 RCC_APB2Periph_AFIO。

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);   //只在此处开启时钟可顺利初始化外部中断
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);    //不配置无法启用外部中断
	
  EXTI_InitStruct.EXTI_Line = EXTI_Line12;
  EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	
  EXTI_Init(&EXTI_InitStruct);
  //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  //只在此处开启时钟不能成功初始化外部中断

对于F2、F4系列,则需要打开

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

“系统配置控制器主要用于管理对可执行代码的存储区的地址重映射。选择以太网PHY接口以及管理GPIO的外部中断连接。”

2、按键处理

按键处理函数TEST_SW(); 每隔50MS在中断处理函数TIM6_IRQHandler();中执行一次。

优点:去抖动检测,不会浪费处理器时间。可用在OS下的按键检测任务。

缺点:非OS下需要定时器定时检测按键。

逻辑

(1)只要按键松开,SW_Key = 0;

(2)第一次检测到按键按下:SW_Key = 0x80;

                        第二次检测:SW_Key = 0x01;

(3)通过判断“SW_Key ==SW_ON” 来判断按键是否按下

#define  SW_ON        1
#define  SW_OFF       0

u8 SW_Key = 0;

void TEST_SW(void)
{
      if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)==0)
	  {
	    SW_Key =  SW_Key>0 ? 0x01:0x80;	
      }
       else
      {
		 SW_Key  = 0;
      }

}	
void TIM6_IRQHandler(void)
{
   TEST_SW();
   TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}

延伸一下,处理多个按键:

//头文件

//按键的数量
#define  KEY_Num  2
 
//按键名称
#define  KEY_0    0
#define  KEY_1    1

//按键有效电平的宏定义
#define  Active_High   1
#define  Active_Low    0
 
//按键检测的宏定义
#define  KeyCheck(GPIO,PIN,FBit,Lev)    (FBit = ( GPIO->IDR & PIN ) ^ ( Lev ? PIN : 0 ) ?  0 : FBit&0x81 ? 1 : 0x80)

//检测按键是否单次触发
//检测完毕后,需再次触发才能检测第二次
#define  KeySingle(FLAG)                (KEY_S.KEY[FLAG]++ == 0x80) 

//检测按键长按
#define  KeyON(FLAG)                    (KEY_S.KEY[FLAG]   == 0x01)

//检测按键是否松开
#define  KeyOFF(FLAG)                   (KEY_S.KEY[FLAG]   == 0)

 
//按键管理结构体
typedef struct
{
	 uint8_t  KEY[KEY_Num];
}KEY_DEV;
 
extern KEY_DEV  KEY_S;
 
 
void  ScanKey(void);

 

//源文件

#include "bsp_key.h"

KEY_DEV  KEY_S;

void  ScanKey(void)
{
    KeyCheck(GPIOA,GPIO_PIN_4, KEY_S.KEY[KEY_0],Active_Low);     //PE2为输出引脚,低电平有效
    KeyCheck(GPIOA,GPIO_PIN_5, KEY_S.KEY[KEY_1],Active_Low);     //PE2为输出引脚,低电平有效
}

 

//中断函数

 

//放进中断程序中,50MS执行一次
void TIM3_IRQHandler(void)
{
	ScanKey();  //按键检测
	
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

//主函数

#include "bsp_key.h"

int main(void)
{
	 int ia = 0; 
	
	 GPIO_Init();
	 TIM_Init();
	
	 while(1)
	 {
	        if(KeySingle(KEY_0))
		{
			ia++;
		}		 
			
		if(KeySingle(KEY_1))
		{
			ia--;
		}
		 
		printf("ia = %d, ",ia);
			
		Delay_MS(1000);
	 }

}

 

使用的时候,先定义好按键宏定义“KEY_Num”,再定义按键名称宏定义,在“ScanKey();”里面添加对应的按键检测宏定义语句即可。之所以用结构体数组成员而不是直接用数组管理按键标志位,是为了以后添加别的功能的时候好管理。

 

 

 

3、定时器捕获的溢出处理

以下是F103捕获PWM频率的溢出处理,TIM分频系数:71,计数器装载值:9999 最低可

捕获1Hz的PWM,全局变量TIM3_FRE保存捕获到的频率值。

u16 TIM3_IC3 = 0,TIM3_Over = 0;
u32 TIM3_FRE=0;

void TIM3_IRQHandler(void)
{
	
	
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) == 1 )
	{
		  TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		  TIM3_Over++;
		  if( (TIM3_Over&0x7f)>99){TIM3_Over=0; TIM3_FRE = 0;}  //循环100次没抓到信号则重新捕获
	}
	else
	{
		 if( (TIM3_Over&0x80) ==0)               //第一次捕获到信号
		{
			TIM3->CNT = 0;
			TIM3_Over = 0x80;			
		}
                else                                    //第二次捕获到信号
		{
			TIM3_IC3 = TIM_GetCapture3(TIM3);
				
			if( (TIM3_Over&0x7f)>0)               //超过一个周期捕获到信号
			{
				TIM3_FRE = 1000000/(TIM3_IC3+(TIM3_Over&0x7f)*10000);
			}
			else                                  //同周期捕获到信号
			{
				TIM3_FRE =1000000/TIM3_IC3;
			}
				TIM3_Over = 0;
		}

		TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
        }
	
}

4、移植F1程序到F2

移植程序到不同系列的MCU其实是挺麻烦的事的。要注意几点:

1、系统时钟频率,包括各AHB总线、APB总线的时钟不同。

2、初始化结构体不同,例如GPIO初始化,F2系列需要设置输出类型、上下拉、模式、引脚号、速度等

     几个结构体成员,而F1只需要设置模式、速度、引脚号就能进行初始化。而且,在设置片上外设引脚时,

     F2还需要设置引脚复用功能。设置方法类似F4系列。

3、外设结构不同。例如DMA。F1系列是不带FIFO的,但是F2是带的。在使用的时候需注意设置对应

     初始化结构体成员。

4、中断函数不同。这点特容易出现难以察觉的错误。例如TIM6,它的中断函数名称在F2是:

void TIM6_DAC_IRQHandler(void)

以及F1中的:

void TIM6_IRQHandler(void)

而且,F1中ADC中断分为ADC1_2以及ADC3两个,但在F2同一为一个ADC中断。

然后是默认初始化的总线分频系数,F1为:

F2是:

如果没留意到这点,在计算外设时钟的时候(ADC或者TIM)就会出现计算错误。

5、STM32 F2标准库函数扇区擦除

当每次仿真运行扇区擦除函数

FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_t VoltageRange);

都会出现错误跳出仿真。当复位MCU时,发现MCU可以正常运行,但是指定的扇区并不能擦除。

仿真跟踪,发现问题出现在如下地方:

    /* if the previous operation is completed, proceed to erase the sector */
    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= tmp_psize;
    FLASH->CR &= SECTOR_MASK;
    FLASH->CR |= FLASH_CR_SER | FLASH_Sector;
    FLASH->CR |= FLASH_CR_STRT;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();   //每次运行到该处,仿真弹出
		

debug下查看寄存器:

CR寄存器的SNB以及PSIZE被清除了,并且PGAERR以及PGPERR这两个标志位置1。

在STM32 的官方文档中对此2标志位描述如下:

可知当PSIZE或者SNB设置错误时,这两个对应的标志位就会置1。

事实上SNB是没有设置错误的,试过设置所有不同的PSIZE还是出现如上错误。

故推测:执行了 FLASH->CR |= FLASH_CR_STRT; 之后

寄存器的SNB以及PSIZE被清零,导致出现以上两个标志位置1。

从手册上并未找出寄存器方面解决的办法,但可以手动添加延时,解决这个问题。

    /* Wait for last operation to be completed */
    delay_ms(2000);
    status = FLASH_WaitForLastOperation();

在添加了2000MS的延时后,仿真不会出错了,扇区也能正常擦除了。

寄存器解决的办法,等研究了STM32CubeMx以及熟悉Hal库后再解决。 


6、SPI快速读取FLASH数据

 

这个方法主要应用在快速读取FLASH数据,然后将数据传输至LCD进行显示。

 

我使用的FLASH为华邦的W25Q系列,LCD控制器为SSD1963.

    u32  i=0, len;  

    LCD_WR_REG(0x002A);	
    LCD_WR_DATA((StartX)>>8);	    
    LCD_WR_DATA((StartX)&0x00ff);
    LCD_WR_DATA((StartX+width-1)>>8);	    
    LCD_WR_DATA((StartX+width-1)&0x00ff);
      LCD_WR_REG(0x002b);	
    LCD_WR_DATA((StartY)>>8);	    
    LCD_WR_DATA((StartY)&0x00ff); 
    LCD_WR_DATA((StartY+heigth-1)>>8);	    
    LCD_WR_DATA((StartY+heigth-1)&0x00ff);
      LCD_WR_REG(0x002c);

    FLASH_L                            	    //使能器件   
	
    SPI_FLASH_SendByte(0x0B);         	    //发送读取命令   
    SPI_FLASH_SendByte((u8)((addr)>>16));  	//发送24bit地址    
    SPI_FLASH_SendByte((u8)((addr)>>8));   
    SPI_FLASH_SendByte((u8)addr); 

    SPI_FLASH_SendByte(0xff); 

    SPI1->CR1 |= 0x0800;      //更改SPI传输数据长度为16bit
    SPI1->CR1 |= SPI_CR1_SPE; //使能SPI外设			

    SPI1->DR = 0xffff;		    //启动传输
    for(i=0;i<SPIReadWaitTime;i++);
		
    len = width*heigth;
		
     while(len--)
    {
       SPI1->DR = 0xffff;
       for(i=0;i<SPIReadWaitTime;i++);
			
       *(u16 *)0x60020000 = SPI1->DR; //数据发送至LCD
    }

    SPI1->CR1 &= 0xf7ff;      //更改SPI传输数据长度为8bit
    FLASH_H  	

“SPIReadWaitTime”为延迟时间宏定义,根据自己MCU速度进行调整。太快将导致数据读取异常。

       主要原理是将SPI数据传输宽度改为16bit,一是为了减少MCU对2个8bit数据进行整合的操作(16bit的LCD)。二是SPI以16bit数据位宽与8bit数据位宽对比,读取同等大小的数据,16bit更快。

       实测8bit下,刷屏速度为14帧/每秒,改为16bit后约为20帧/每秒。

7、定时器中断导致的逻辑错误

int t4 = 0;

void TIM4_IRQHandler(void)
{
	t4 = 1;
	TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}

int main(void)
{
	TIM_Cmd(TIM4, ENABLE); //TIM4 启动后100us进入更新中断

	t4 = 0;

	Delay_MS(1);

	if (t4 == 0)  LCD_DIS(LOGO); //此处的LCD_DIS(LOGO);不会被执行,因为定时器中断将t4置为:1

	while (1)
	{
		//code
	}

}

定时器中使用到的变量以及功能函数,若是主循环中也使用,应谨防此类错误

 

8、SPI标准库函数问题

硬件环境是STM32F205VCT6,F2使用标准库。

对SPI FLASH进行读写,WQX256。SPI分频系数为2

u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) 
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI1->DR = TxData;
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //这一步,跳出while后,仿真检测到retry为0
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI1->DR; //返回通过SPIx最近接收的数据		
}

如上SPI读写函数,在进行SPI  DUMMY读写的时候,仿真中检测到“retry = 0;”,即SPI库中的标志位检测函数没有检测到正确的

标志位。但后续SPI读写,数据确是正确的。

这就导致了读写前2个字节会出现错误的数据。解决方法是添加DUMMY的功能:

void SPI_RW_DUMMY(void)
{
	  u8 i;
	  SPI1->DR = 0xff;			
	  for(i=0;i<50;i++);  //这个延时时间可自行定义
	  i = SPI1->DR; 
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ​ STM32-STLink是一款常见的STM32单片机的USB调试工具,它可以方便地进行芯片的程序下载、烧录、调试和监测工作。在使用STM32-STLink进行调试工作前,需要先安装STM32-STLink驱动。 STM32-STLink驱动可以在ST官网或软件开发社区中获取。在安装驱动前需要确保电脑已经连接上STM32-STLink,并且已经准备好了相应的开发环境。建议先卸载旧版本的驱动再进行安装。 具体操作步骤如下: 1. 连接STM32-STLink到电脑,确保正常供电和通信。 2. 安装驱动,可以从ST官网或者软件开发社区中下载最新驱动程序。 3. 解压下载的驱动程序,双击运行安装程序。 4. 驱动安装过程中需要注意选择与自己操作系统版本相对应的驱动程序,勾选“核心组件”和“驱动程序”选项,进行安装。 5. 安装完成后,重启电脑,确认驱动程序已经成功安装。 6. 打开开发环境,并连接STM32-STLink,进行调试工作。在调试过程中,可以通过STLink Utility等工具进行芯片的操作。 总之,STM32-STLink驱动是STM32单片机开发必备的驱动程序之一。通过安装该驱动,可以方便地进行芯片的调试工作和程序烧录操作。 ### 回答2: stm32-stlink驱动是一种用于连接STM32单片机与电脑的驱动。STM32是一种低功耗、高性能的32位微控制器,而stlink是一种芯片级调试工具,用于将计算机与STM32单片机连接起来,进行程序的调试和下载。由于stm32-stlink驱动具备高性能、可靠性和灵活性等优势,因此在计算机与STM32单片机之间的数据传输过程中发挥了重要作用。 stm32-stlink驱动可以实现多种不同的功能。例如,在调试过程中,它可以帮助开发者调试程序,并实时监测STM32单片机的运行情况。此外,该驱动还可以实现对单片机的程序下载、烧录、刷写等操作,方便开发者进行快速迭代和测试。 除了实现上述功能之外,stm32-stlink驱动还具备多种其他特点。例如,该驱动可以长时间稳定运行,且不会对系统稳定性产生不利影响。此外,该驱动还具备自动适配的能力,可以适应不同版本的STM32单片机。 在使用stm32-stlink驱动之前,开发者需要根据自己的需要进行安装和配置。具体来说,需要下载适合自己系统版本的stm32-stlink驱动,并在电脑上安装。此外,在进行开发过程中,开发者还需要根据需要对该驱动进行相应的设置和调整,以保障程序的正常运行。 总的来说,stm32-stlink驱动是一种实现STM32单片机与电脑之间数据传输的重要工具,具备多种优势和特点。在进行相关开发工作时,合理配置和使用该驱动可以极大地提高开发效率和程序稳定性。 ### 回答3: STM32-STLINK驱动是用于连接计算机和STM32微控制器开发板之间的软件程序。STM32-STLINK驱动可用于下载代码,调试和仿真微控制器。STM32-STLINK驱动由STMicroelectronics提供,并且是免费提供的。该驱动程序可以在Windows和Linux操作系统上使用,并且支持多种开发工具,例如Keil,IAR和Atollic。 在使用STM32-STLINK驱动之前,需要先将开发板与计算机连接。连接过程可以通过USB连接或JTAG/SWD接口完成。当前,STMicroelectronics生产的大多数STM32微控制器都具有内置的ST-LINK / V2-1调试器,因此无需单独购买ST-LINK外设。只需使用USB线缆将STM32板连接到计算机上,即可使用STM32-STLINK驱动。 一旦STM32开发板和计算机连接成功并且安装了STM32-STLINK驱动,就可以开始进行下载、调试和仿真微控制器的工作了。STM32-STLINK驱动提供了基本的调试工具,例如设置断点、查看变量和跟踪程序执行等功能,以帮助开发人员进行程序调试。此外,该驱动程序还支持许多高级功能,例如实时追踪、功耗分析和定时器分析等,以帮助开发人员更深入地了解和优化代码。 综上所述,STM32-STLINK驱动是连接STM32微控制器和计算机之间的关键软件程序,用于下载、调试和仿真微控制器。它具有易于使用和灵活的优点,是STM32开发的重要工具之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值