解读set_gpio_ctrl(GPIO_MODE_OUT | GPIO_H6)

转自:http://wang11qiang11.blog.163.com/blog/static/9803010920090604541334/

 

 做嵌入式底层的东西,初始化硬件设备应该是必须的。一个个内核调用函数足以让人头晕!   

    最近在看Linux嵌入式(s3c2410)方面的内容,遇到了这样一个函数:set_gpio_ctrl(); 它从字面上看来是对gpio口的设置扩展。GPIO是什么呢?它是通用 IO端口引脚,在s3c2410用户手册中有A,B,C,D,E,F,G,H7组共117个引脚。这些引脚除了可作为INPUT/OUTPUT外,大部份还可以用作其它用,如外部中断,UART等。它们用的控制寄存器主要有GPACON-GPHCON,GPADAT-GPHDAT,GPBUP- GPHUP,还有一些不累赘了。
       我在linux内核原代码的/include/asm-arm/arch-s3c2410/s3c2410.h 这头文件个找到set_gpio_ctrl()函数的定义,体质来讲是个宏定义。以下是我记录下的一段相关代码,我将依照这段代码来分析。想必刚开始看这一段东西,一般人都会头痛,我也是。但这是必须通过的一道门槛,所以我们应该学会抓住重点分析。
#define GPCON(x) __REG2(0x56000000, (x) * 0x10)       //(此为GPACON---GPHCON 的一种表示)
#define GPDAT(x) __REG2(0x56000004, (x) * 0x10)       //(此为GPADAT--GPHDAT 的一种表示)
#define GPUP(x) __REG2(0x56000008, (x) * 0x10)

#define GPIO_OFS_SHIFT  0
#define GPIO_PORT_SHIFTT 8
#define GPIO_PULLUP_SHIFT 16
#define GPIO_MODE_SHIFT  24
#define GPIO_OFS_MASK  0x000000ff
#define GPIO_PORT_MASK  0x0000ff00
#define GPIO_PULLUP_MASK 0x00ff0000
#define GPIO_MODE_MASK  0xff000000
#define GPIO_MODE_IN  (0 << GPIO_MODE_SHIFT)
#define GPIO_MODE_OUT  (1 << GPIO_MODE_SHIFT)
#define GPIO_MODE_ALT0  (2 << GPIO_MODE_SHIFT)
#define GPIO_MODE_ALT1  (3 << GPIO_MODE_SHIFT)
#define GPIO_PULLUP_EN  (0 << GPIO_PULLUP_SHIFT)
#define GPIO_PULLUP_DIS  (1 << GPIO_PULLUP_SHIFT)
#define PORTA_OFS  0
#define PORTB_OFS  1
#define PORTC_OFS  2
#define PORTD_OFS  3
#define PORTE_OFS  4
#define PORTF_OFS  5
#define PORTG_OFS  6
#define PORTH_OFS  7
#define MAKE_GPIO_NUM(p, o) ((p << GPIO_PORT_SHIFTT) | (o << GPIO_OFS_SHIFT))
#define GRAB_MODE(x)  (((x) & GPIO_MODE_MASK) >> GPIO_MODE_SHIFT)
#define GRAB_PULLUP(x)  (((x) & GPIO_PULLUP_MASK) >> GPIO_PULLUP_SHIFT)
#define GRAB_PORT(x)  (((x) & GPIO_PORT_MASK) >> GPIO_PORT_SHIFTT)
#define GRAB_OFS(x)  (((x) & GPIO_OFS_MASK) >> GPIO_OFS_SHIFT)
                                        #set_gpio_ctrl(GPIO_MODE_OUT|GPIO_F6) 设置相应GPIO位是输入还是输出
#define set_gpio_ctrl(x) /
 ({ GPCON(GRAB_PORT((x))) &= ~(0x3 << (GRAB_OFS((x))*2)); /
    GPCON(GRAB_PORT(x)) |= (GRAB_MODE(x) << (GRAB_OFS((x))*2)); /
    GPUP(GRAB_PORT((x))) &= ~(1 << GRAB_OFS((x))); /
    GPUP(GRAB_PORT((x))) |= (GRAB_PULLUP((x)) << GRAB_OFS((x))); })
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#define set_gpioA_mode(x) /
 ({ GPCON(GRAB_PORT((x))) &= ~(0x1 << GRAB_OFS((x))); /
    GPCON(GRAB_PORT((x))) |= (GRAB_MODE((x)) << GRAB_OFS((x))); })
#define read_gpio_bit(x) ((GPDAT(GRAB_PORT((x))) & (1<<GRAB_OFS((x)))) >> GRAB_OFS((x)))
#define read_gpio_reg(x) (GPDAT(GRAB_PORT((x)))
#define write_gpio_bit(x, v) /
 ({ GPDAT(GRAB_PORT((x))) &= ~(0x1 << GRAB_OFS((x))); /
    GPDAT(GRAB_PORT((x))) |= ((v) << GRAB_OFS((x))); })
#define write_gpio_reg(x, v) (GPDAT(GRAB_PORT((x))) = (v))
 
#define GPIO_A0    MAKE_GPIO_NUM(PORTA_OFS, 0)
#define GPIO_A1    MAKE_GPIO_NUM(PORTA_OFS, 1)
::::::::::::::::::::
#define GPIO_A21   MAKE_GPIO_NUM(PORTA_OFS, 21)
#define GPIO_A22   MAKE_GPIO_NUM(PORTA_OFS, 22)
 
#define GPIO_H0    MAKE_GPIO_NUM(PORTH_OFS, 0)
#define GPIO_H6    MAKE_GPIO_NUM(PORTH_OFS, 6)
::::::::::::::::::::
#define GPIO_H10   MAKE_GPIO_NUM(PORTH_OFS, 10)
 
#define GPIO_MODE_nXBACK  GPIO_MODE_ALT0
:::::::::::::::::::::;;;
#define GPIO_MODE_LCD_PWRDN  GPIO_MODE_ALT1
 
  第一个要明白的是GPCON(x)。GPACON-GPHCON为端口控制寄存器。其起始地趾为0x56000000
#define GPCON(x) __REG2(0x56000000, (x) * 0x10)       x的取值为0-7对应GPACON---GPHCON 的地址。
#define GPDAT(x) __REG2(0x56000004, (x) * 0x10)        #(此为GPADAT--GPHDAT 的一种表示)
#define GPUP(x) __REG2(0x56000008, (x) * 0x10)         也是一样的道理。
  第二个是 GPIO_OFS_SHIFT  GPIO_PORT_SHIFT  GPIO_PULLUP_SHIFT  GPIO_MODE_SHIFT 。s3c2410.h中是这样定义的:
#define GPIO_OFS_SHIFT          0                                  #define GPIO_OFS_MASK  0x000000ff
#define GPIO_PORT_SHIFTT     8        相对应              #define GPIO_PORT_MASK  0x0000ff00
#define GPIO_PULLUP_SHIFT 16                                  #define GPIO_PULLUP_MASK 0x00ff0000
#define GPIO_MODE_SHIFT      24                                 #define GPIO_MODE_MASK  0xff000000
他们的作用是什么呢,为什么要这样定义呢?我们都知道对硬件的初始化和操作有很大一部分是对其相对应的寄存器的操作。说白一点也就是对相应位置 0或1。s3c2410的寄存器是32位的,再来看一下set_gpio_ctrl(GPIO_MODE_OUT |  GPIO_H6)中的参数:GPIO_MODE_OUT |  GPIO_H6。它表示将端口组H的6端口设置成输出模式(MODE)。看一下参数命令的结构,这很重要,是突破点:这命令化成数值是32位的,高位为GPIO_MODE_OUT, 低位为GPIO_H6。那么GPIO_MODE_OUT和GPIO_H6又是什么呢,再看几个定义:
#define GPIO_MODE_IN       (0 << GPIO_MODE_SHIFT)
#define GPIO_MODE_OUT   (1 << GPIO_MODE_SHIFT)
#define GPIO_MODE_ALT0  (2 << GPIO_MODE_SHIFT)
#define GPIO_MODE_ALT1  (3 << GPIO_MODE_SHIFT)
#define GPIO_PULLUP_EN  (0 << GPIO_PULLUP_SHIFT)
#define GPIO_PULLUP_DIS  (1 << GPIO_PULLUP_SHIFT) 
###MODE_IN,MODE_OUT,MODE_  是表示端口的作用是输入输出还是另作它用。
#为什么要用0,1来左移呢?s3c2410数据手册告诉我们00表示输入01表示输出
#GPIO_MODE_SHIFT=24即把00或01搬到第24位去:  1  0000 0000 0000 0000 0000 0000
##或 0  0000 0000 0000 0000 0000 0000(这是用32位中的位24-31来表示端口的作用)
##那么命令中的GPIO_H6:即哪个端口组的哪个端口又是如何表示的?看看下面的
#define GPIO_OFS_SHIFT  0 
#define GPIO_PORT_SHIFTT 8       
#define GPIO_PULLUP_SHIFT 16
 
#define PORTA_OFS  0 ##和#define GPIO_MODE_SHIFT  24  看看,我们大致可以猜到:(这是这是用32位中的位16-23来表示要设置某个端口的上拉功能)
#define PORTB_OFS  1 ##(这是用32位中的位8-15来表示要设置哪一个端口组)
#define PORTC_OFS  2  ###(这是用32位中的位0-7来表示要设置一个端口组的哪一个端口)
#define PORTD_OFS  3  #那么类似GPIO_H6是如何构造的?看下面的宏定义,我们展开:
#define PORTE_OFS  4 #GPIO_H6=MAKE_GPIO_NUM(7, 6)
#define PORTF_OFS  5 #= ( (7<<8) | (6<<0))= ( 111 0000 0000  |  110)=111 0000 110   
#define PORTG_OFS  6#看出程序把端口组A-H用0-7表示放在8-15位
#define PORTH_OFS  7##端口组中具体端口则放在0-7位
                               #MAKE_GPIO_NUM(p, o)这个宏就是构造这样的
            
#define MAKE_GPIO_NUM(p, o) ((p << GPIO_PORT_SHIFTT) | (o << GPIO_OFS_SHIFT))
#define GPIO_H6    MAKE_GPIO_NUM(PORTH_OFS, 6)
 
       前面分析了参数命令的构造,那么如何解释命令呢?
#define GRAB_MODE(x)  (((x) & GPIO_MODE_MASK) >> GPIO_MODE_SHIFT)
#define GRAB_PULLUP(x)  (((x) & GPIO_PULLUP_MASK) >> GPIO_PULLUP_SHIFT)
#define GRAB_PORT(x)  (((x) & GPIO_PORT_MASK) >> GPIO_PORT_SHIFTT)
#define GRAB_OFS(x)  (((x) & GPIO_OFS_MASK) >> GPIO_OFS_SHIFT)
grab顾名思义,是抓取的意思。GRAB_MODE(x)是把命令的端口模式取出,得到的是一8位的值。GRAB_PORT(x)得到端口组,GRAB_OFS(x)得到端口号。
 
        最重要的已经分析完了,在回过头来看一下set_gpio_ctrl()
 #define set_gpio_ctrl(x) /
 ({ GPCON(GRAB_PORT((x))) &= ~(0x3 << (GRAB_OFS((x))*2)); /
    GPCON(GRAB_PORT(x)) |= (GRAB_MODE(x) << (GRAB_OFS((x))*2)); /
    GPUP(GRAB_PORT((x))) &= ~(1 << GRAB_OFS((x))); /
    GPUP(GRAB_PORT((x))) |= (GRAB_PULLUP((x)) << GRAB_OFS((x))); })       

 GPCON(GRAB_PORT((x)))   表示一个端口组的控制寄存器.
在控制寄存器.里是用2位来表示去功能:0-1表示0端口,2-3表示1端口;;;;;
所以GRAB_OFS((x))*2 表示这个端口号是从寄存器的第几位开始.
GPCON(GRAB_PORT((x))) &= ~(0x3 << (GRAB_OFS((x))*2)); 表示把对应位清0.
以下类似,不一一表书.

#include "stm32f10x.h" // ???? void Timer4_Init(u16 Period); void led_init(void); void key_init(void); void delay_init(void); void delay_us(u32 nus); void delay_ms(u16 nms); uint8_t KEY_Scan(uint8_t mode); void play_music(void); void change_song(int direction); void show_song_info(void); // ?????? static u8 fac_us = 0; // us????? static u16 fac_ms = 0; // ms????? // ???? #define proport 10000 // Tclk/(psc+1)=72000000/(7199+1) #define L1 ((proport/131)-1) // ?? do ?? #define L2 ((proport/147)-1) // ?? re ?? #define L3 ((proport/165)-1) // ?? mi ?? #define L4 ((proport/176)-1) // ?? fa ?? #define L5 ((proport/196)-1) // ?? sol ?? #define L6 ((proport/220)-1) // ?? la ?? #define L7 ((proport/247)-1) // ?? si ?? #define M1 ((proport/262)-1) // ?? do ?? #define M2 ((proport/296)-1) // ?? re ?? #define M3 ((proport/330)-1) // ?? mi ?? #define M4 ((proport/349)-1) // ?? fa ?? #define M5 ((proport/392)-1) // ?? sol ?? #define M6 ((proport/440)-1) // ?? la ?? #define M7 ((proport/494)-1) // ?? si ?? #define H1 ((proport/523)-1) // ?? do ?? #define H2 ((proport/587)-1) // ?? re ?? #define H3 ((proport/659)-1) // ?? mi ?? #define H4 ((proport/699)-1) // ?? fa ?? #define H5 ((proport/784)-1) // ?? sol ?? #define H6 ((proport/880)-1) // ?? la ?? #define H7 ((proport/988)-1) // ?? si ?? // ???? #define KEY0 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) // K0??:PA3 #define KEY1 GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_4) // K1??:PC4 // ???? const int music1[] = // ???? { M5, 50, M5, 25, M5, 25, M6, 100, M5, 100, H1, 100, M7, 100, M7, 100, M5, 50, M5, 25, M5, 25, M6, 100, M5, 100, H2, 100, H1, 100, H1, 100, M5, 50, M5, 25, M5, 25, H5, 100, H3, 100, H1, 100, M7, 100, M6, 100, H4, 50, H4, 25, H4, 25, H3, 100, H1, 100, H2, 100, H1, 100, H1, 100 }; const int music2[] = // ???? { M1, 100, M2, 100, M3, 100, M1, 100, M1, 100, M2, 100, M3, 100, M1, 100, M3, 100, M4, 100, M5, 200, M3, 100, M4, 100, M5, 200, M5, 50, M6, 50, M5, 50, M4, 50, M3, 100, M1, 100, M5, 50, M6, 50, M5, 50, M4, 50, M3, 100, M1, 100, M1, 100, M5, 100, M1, 200, M1, 100, M5, 100, M1, 200 }; const int music3[] = // ??? { M1, 100, M1, 100, M5, 100, M5, 100, M6, 100, M6, 100, M5, 200, M4, 100, M4, 100, M3, 100, M3, 100, M2, 100, M2, 100, M1, 200, M5, 100, M5, 100, M4, 100, M4, 100, M3, 100, M3, 100, M2, 200, M5, 100, M5, 100, M4, 100, M4, 100, M3, 100, M3, 100, M2, 200, M1, 100, M1, 100, M5, 100, M5, 100, M6, 100, M6, 100, M5, 200, M4, 100, M4, 100, M3, 100, M3, 100, M2, 100, M2, 100, M1, 200 }; // ??????????? const int* music_list[] = {music1, music2, music3}; const int music_length[] = {sizeof(music1)/sizeof(music1[0]), sizeof(music2)/sizeof(music2[0]), sizeof(music3)/sizeof(music3[0])}; const char* music_names[] = {"????", "????", "???"}; int current_music = 0; // ???????? int music_count = 3; // ???? // ?????? volatile uint8_t music_playing = 0; // ?????? volatile uint8_t song_changed = 0; // ??????? uint8_t is_paused = 0; // ???? int main() { delay_init(); // ??????? led_init(); // ???LED key_init(); // ????? show_song_info(); // ???????? while (1) { // ??????? uint8_t key = KEY_Scan(0); if (key == 1) { // K0??,??? change_song(1); } else if (key == 2) { // K1??,??? change_song(-1); } // ??????:K0?K1???? if (KEY0 == 0 && KEY1 == 0) { delay_ms(50); // ?? if (KEY0 == 0 && KEY1 == 0) { is_paused = !is_paused; if (is_paused) { Timer4_Init(0); // ???? } else { // ????????? music_playing = 0; } while(KEY0 == 0 && KEY1 == 0); // ?????? } } // ????(????) if (!is_paused && !music_playing && !song_changed) { play_music(); } // ?????? if (song_changed) { song_changed = 0; show_song_info(); } } } // ????????? void play_music(void) { const int* music = music_list[current_music]; int length = music_length[current_music]; int i; music_playing = 1; for (i = 0; i < (length / 2); i++) { // ????????????? if (song_changed || is_paused) { Timer4_Init(0); // ???? music_playing = 0; return; } Timer4_Init(music[2 * i]); // ??PWM??(??) delay_ms(5 * music[2 * i + 1]); // ?????? // ??????? Timer4_Init(0); delay_ms(20); } delay_ms(1000); // ????????? music_playing = 0; } // ???? void change_song(int direction) { // ??????,??? if (music_playing) { song_changed = 1; // ???????? while(music_playing); } // ????????? current_music += direction; if (current_music >= music_count) current_music = 0; if (current_music < 0) current_music = music_count - 1; // ???????? Timer4_Init(H1); delay_ms(200); Timer4_Init(0); song_changed = 1; } // ????????(??LED??) void show_song_info(void) { int i; // ????LED GPIO_SetBits(GPIOB, GPIO_Pin_5); GPIO_SetBits(GPIOE, GPIO_Pin_5); // ??????(3?) for (i = 0; i < 3; i++) { GPIO_ResetBits(GPIOB, GPIO_Pin_5); delay_ms(150); GPIO_SetBits(GPIOB, GPIO_Pin_5); delay_ms(100); } delay_ms(300); // ???????? for (i = 0; i < current_music + 1; i++) { GPIO_ResetBits(GPIOB, GPIO_Pin_5); delay_ms(200); GPIO_SetBits(GPIOB, GPIO_Pin_5); delay_ms(150); } delay_ms(500); // ????????(??LED????) if (current_music == 0) { // ???? for (i = 0; i < 3; i++) { // PB5??3? GPIO_ResetBits(GPIOB, GPIO_Pin_5); delay_ms(100); GPIO_SetBits(GPIOB, GPIO_Pin_5); delay_ms(100); } delay_ms(200); for (i = 0; i < 2; i++) { // PE5??2? GPIO_ResetBits(GPIOE, GPIO_Pin_5); delay_ms(200); GPIO_SetBits(GPIOE, GPIO_Pin_5); delay_ms(200); } } else if (current_music == 1) { // ???? for (i = 0; i < 2; i++) { // PB5??2? GPIO_ResetBits(GPIOB, GPIO_Pin_5); delay_ms(100); GPIO_SetBits(GPIOB, GPIO_Pin_5); delay_ms(100); } delay_ms(200); for (i = 0; i < 2; i++) { // PE5??2? GPIO_ResetBits(GPIOE, GPIO_Pin_5); delay_ms(100); GPIO_SetBits(GPIOE, GPIO_Pin_5); delay_ms(100); } } else { // ??? for (i = 0; i < 3; i++) { // PB5??3? GPIO_ResetBits(GPIOB, GPIO_Pin_5); delay_ms(200); GPIO_SetBits(GPIOB, GPIO_Pin_5); delay_ms(200); } } delay_ms(1000); } // ???4???,??PWM??(???????) void Timer4_Init(u16 Period) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCStructure; // ?????????(???0) if (Period == 0) { TIM_Cmd(TIM4, DISABLE); // ????? return; } RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // ??TIM4?? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // ??GPIOB?? // ??PB8???????(TIM4_CH3) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // ??TIM4?? TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // ?????? TIM_TimeBaseStructure.TIM_Period = Period; // ??????(????) TIM_TimeBaseStructure.TIM_Prescaler = 7199; // ????(72MHz/7200=10kHz) TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // ??PWM?? TIM_OCStructure.TIM_OCMode = TIM_OCMode_PWM2; // PWM??2 TIM_OCStructure.TIM_OCPolarity = TIM_OCPolarity_High; // ????? TIM_OCStructure.TIM_OutputState = TIM_OutputState_Enable; // ???? TIM_OCStructure.TIM_Pulse = Period / 2; // ????50%(???) TIM_OC3Init(TIM4, &TIM_OCStructure); TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); // ???????? TIM_Cmd(TIM4, ENABLE); // ????? } // LED????? void led_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE); // ??PB5????? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // ??PE5????? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOE, &GPIO_InitStructure); // ????LED?? GPIO_SetBits(GPIOB, GPIO_Pin_5); GPIO_SetBits(GPIOE, GPIO_Pin_5); } // ????? void key_init(void) { GPIO_InitTypeDef GPIO_InitStructure; // ??GPIOA?GPIOC?? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE); // ??PA3?????(K0??) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // ??PC4?????(K1??) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_Init(GPIOC, &GPIO_InitStructure); } // ?????? uint8_t KEY_Scan(uint8_t mode) { static uint8_t key_up = 1; // ?????? if (mode) key_up = 1; // ???? if (key_up && (KEY0 == 0 || KEY1 == 0)) { delay_ms(15); // ???????15ms key_up = 0; if (KEY0 == 0) return 1; // K0?? if (KEY1 == 0) return 2; // K1?? } else if (KEY0 == 1 && KEY1 == 1) { key_up = 1; } return 0; // ????? } // ??????? void delay_init(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); // ??SysTick???HCLK/8 fac_us = SystemCoreClock / 8000000; // 72MHz??????9 fac_ms = (u16)fac_us * 1000; // 9000,1ms??9000?SysTick?? } // ??????? void delay_us(u32 nus) { u32 temp; SysTick->LOAD = nus * fac_us; // ???????? SysTick->VAL = 0x00; // ????? SysTick->CTRL |= SysTick_CTRL_ENABLE; // ????? do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); // ?????? SysTick->CTRL &= ~SysTick_CTRL_ENABLE; // ????? SysTick->VAL = 0X00; // ????? } // ??????? void delay_ms(u16 nms) { u32 temp; SysTick->LOAD = (u32)nms * fac_ms; // ???????? SysTick->VAL = 0x00; // ????? SysTick->CTRL |= SysTick_CTRL_ENABLE; // ????? do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); // ?????? SysTick->CTRL &= ~SysTick_CTRL_ENABLE; // ????? SysTick->VAL = 0X00; // ????? }
06-20
void my_delay(int n) { int i = 0; while(n--) for(i=0; i<8050; i++); } #define proport 10000 #define L1 ((proport/131)-1)//低调 do 的周期 #define L2 ((proport/147)-1)//低调 re 的周期 #define L3 ((proport/165)-1)//低调 mi 的周期 #define L4 ((proport/176)-1)//低调 fa 的周期 #define L5 ((proport/196)-1)//低调 sol 的周期 #define L6 ((proport/220)-1)//低调 la的周期 #define L7 ((proport/247)-1)//低调 si 的周期 #define M1 ((proport/262)-1)//低调 do 的周期 #define M2 ((proport/296)-1)//低调 re 的周期 #define M3 ((proport/330)-1)//低调 mi 的周期 #define M4 ((proport/349)-1)//低调 fa 的周期 #define M5 ((proport/392)-1)//低调 sol 的周期 #define M6 ((proport/440)-1)//低调 la 的周期 #define M7 ((proport/494)-1)//低调 si 的周期 #define H1 ((proport/523)-1)//低调 do 的周期 #define H2 ((proport/587)-1)//低调 re 的周期 #define H3 ((proport/659)-1)//低调 mi 的周期 #define H4 ((proport/699)-1)//低调 fa 的周期 #define H5 ((proport/784)-1)//低调 sol 的周期 #define H6 ((proport/880)-1)//低调 la 的周期 #define H7 ((proport/988)-1)//低调 si 的周期void Pwm_Gpio_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA的时钟 //GPIO配置 PA6 TIM3_CH1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); //引脚初始化 } void Tim2_Pwm_Set(int Period, int Pulse) { TIM_TimeBaseInitTypeDef TIM_BaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIM3的时钟 //TIM2的基本配置 TIM_BaseInitStructure.TIM_Prescaler = 7200-1;//预分频 TIM_BaseInitStructure.TIM_Period = Period;//计数周期 TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割 输入滤波 TIM_TimeBaseInit(TIM2, &TIM_BaseInitStructure);//初始化TIM2 //配置TIM2的通道1输出PWM脉冲 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM 脉冲宽度调制模式 1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//定时器输出使能 TIM_OCInitStructure.TIM_Pulse = Pulse;//设置装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM 输出比较极性:高 即周期内低于TIM_Pulse这个阈值的时间,都是高电平,其他时间都是低; TIM_OC1Init(TIM2,&TIM_OCInitStructure);//初始化TIM2的Channel1 TIM_Cmd(TIM2,ENABLE);//使能TIM2 } void Set_Rate(int rate) { if((rate >= 0) && (rate < 400)) TIM_SetCompare1(TIM2, rate); else return;int music1[]= { M5,50,M5,25,M5,25, M6,100,M5,100,H1,100, M7,100,M7,100,M5,50,M5,25,M5,25, M6,100,M5,100,H2,100, H1,100,H1,100,M5,50,M5,25,M5,25, H5,100,H3,100,H1,100, M7,100,M6,100,H4,50,H4,25,H4,25, H3,100,H1,100,H2,100,H1,100,H1,100 };music1是生日快乐歌,我需要你写出警报时的警报音
03-22
### 设置GPIO模式的函数用法 在嵌入式开发中,`HAL_GPIO_Init` 函数通常用于初始化指定的 GPIO 引脚配置。然而,在提供的引用材料中并没有直接提到 `set_gpio_mode` 这样的命名方式。相反的是,通过结构体来设定 GPIO 的工作模式。 #### 使用 `gpio_config_t` 结构体设置 GPIO 模式 为了设置 GPIO 工作模式,可以通过填充 `gpio_config_t` 类型的结构体成员实现[^4]: ```c // 定义并初始化 gpio 配置结构体 gpio_config_t io_conf; io_conf.pin_bit_mask = (1ULL << 0); // 设置位掩码为第 0 号引脚 io_conf.mode = GPIO_MODE_OUTPUT; // 设定为输出模式 io_conf.pull_up_en = GPIO_PULLUP_DISABLE;// 关闭上拉电阻 io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; // 关闭下拉电阻 io_conf.intr_type = GPIO_INTR_DISABLE; // 禁用中断功能 ``` 接着利用上述已配置好的结构体去调用相应的初始化接口完成实际硬件资源分配与属性应用过程。这里假设存在一个名为 `ESP_ERROR_CHECK(gpio_config(&io_conf))` 的宏用来执行错误检测以及真正的初始化操作。 需要注意的是不同平台可能有不同的 API 接口名称和参数定义形式,以上例子基于 ESP-IDF SDK 编程环境下的情况描述。 对于 STM32 平台,则会采用 HAL 库的方式来进行类似的配置: ```c GPIO_InitTypeDef GPIO_InitStruct; /*Configure GPIO pin : PA0 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); ``` 这段代码展示了如何针对特定引脚(PA0)进行推挽输出模式、无上下拉状态及低速频率特性的初始化设置[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值