day12:位带操作

STM32F103RCT6支持位带操作,但是现在的ST的高端产品已经不支持位带操作了,因为ARM公司提供的内核已经不支持,所以ST公司也无能为力。

位带操作指的是操作IO口的位,比如51单片机当中的sbit P0^0 = 0;(或者P0^0 = 0x00;),这样,可以直接控制某个位输出高电平或者低电平

外设与SRAM位带区与位带别名区的地址统一用一个公式 表示

((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bitnum<<2))

addr:要操作的位所在寄存器的地址,怎么查询到?这是寄存器的端口的真实地址(等于基地址+地址偏移,查看STM32的官方手册)
bitnum:位号,即在寄存器的第几位。比如D4这个LED的端口是PC2,那bitnum=2。

下面,使用位带操作来实现PC2和PC3两个LED灯的流水灯效果

=============================================

bsp_led.h:

/* 和LED功能模块相关的程序 */
 
#ifndef __BSP_LED_H__
#define __BSP_LED_H__
 
#include "stm32f10x.h"
 
/*宏定义*/
#define GPIO_CLK_D4         RCC_APB2Periph_GPIOC        // 时钟
#define GPIO_PORT_D4        GPIOC                       // C端口
#define GPIO_PIN_D4         GPIO_Pin_2                  // PC2引脚
 
#define GPIO_CLK_D5         RCC_APB2Periph_GPIOC        // 时钟
#define GPIO_PORT_D5        GPIOC                       // C端口
#define GPIO_PIN_D5         GPIO_Pin_3                  // PC2引脚
 
/*配置GPIO*/
void LED_GPIO_Config(void);
 
#endif  /*__BSP_LED_H__*/

 bsp_led.c:

/* 和LED功能模块相关的程序头文件 */
 
#include "./led/bsp_led.h"  /*绝对路径,也可在Options for target中设置头文件*/
 
/*GPIO初始化*/
void LED_GPIO_Config(void)
{
    /*外设结构体*/
    GPIO_InitTypeDef GPIO_InitStruct_D4, GPIO_InitStruct_D5;   
     
    /*第一步:打开外设的时钟,看stm32f10x_rcc.c这个文件的RCC_APB2PeriphClockCmd函数介绍*/
    RCC_APB2PeriphClockCmd(GPIO_CLK_D4, ENABLE);
     
    /*第二步:配置外设的初始化结构体*/
    GPIO_InitStruct_D4.GPIO_Pin = GPIO_PIN_D4;          // PC2的那盏LED灯(D4)的引脚
    GPIO_InitStruct_D4.GPIO_Mode = GPIO_Mode_Out_PP;    // 推挽输出模式
    GPIO_InitStruct_D4.GPIO_Speed = GPIO_Speed_10MHz;   // 引脚速率
     
    GPIO_InitStruct_D5.GPIO_Pin = GPIO_PIN_D5;          // PC3的那盏LED灯(D5)的引脚
    GPIO_InitStruct_D5.GPIO_Mode = GPIO_Mode_Out_PP;    // 推挽输出模式
    GPIO_InitStruct_D5.GPIO_Speed = GPIO_Speed_10MHz;   // 引脚速率
     
    /*第三步:调用外设初始化函数,把配置好的结构体成员写到寄存器里面*/
    GPIO_Init(GPIO_PORT_D4, &GPIO_InitStruct_D4);
    GPIO_Init(GPIO_PORT_D5, &GPIO_InitStruct_D5);
}

 main.c:

#include "stm32f10x.h"
#include "./led/bsp_led.h"

/*
* 参数宏定义:
* 后面是公式,直接拷贝进来,输入寄存器端口的真实地址和位的序号就可以了
*/
#define PCout(n) (*(unsigned int*)(((GPIOC_BASE+0X0C) & 0xF0000000)+0x02000000+(((GPIOC_BASE+0X0C) & 0x000FFFFF)<<5)+(n<<2)))

// 延迟函数
void delay(unsigned int i)
{
    for(; i!=0; i--);
}

int main(void)
{
	/* LED初始化 */
	LED_GPIO_Config();
	
	while(1)
	{
		/* D4亮,D5灭 */
		PCout(2) = 0;
		PCout(3) = 1;
		delay(0XFFFFF);
		
		/* D5亮,D4灭 */
		PCout(2) = 1;
		PCout(3) = 0;
		delay(0XFFFFF);
	}
}

实验现象:

D4和D5两个LED灯轮流闪烁,实现了流水灯(跑马灯)的效果

 

posted @ 2018-04-29 17:19  半生戎马,共话桑麻、  阅读(211)  评论(0)    收藏  举报
levels of contents