22302|52

78

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

STM32初学者笔记(1)一步步建立自己的STM32函数 [复制链接]

STM32初学者笔记(1) 一步步建立自己的STM32函数
使用自己建立的 STM32F103.H 的 头文件。里面有大量中文注释。非常适合初学者。

STM32的库实在太庞大负责,对初学者来说实在是件头痛的事情!

下面是万利开发板 LCD DEMO 例子中的函数,改后初学者可以对照学习一下。


//=========================================================================
//     原函数名称: RCC_Configuration(void)
//=========================================================================
void STM32_RCC_Configuration(void)
{

    STM32_Rcc_Regs->cr.bit.HSEON=0;        // HSE振荡器开启关闭
    STM32_Rcc_Regs->cr.bit.HSEBYP=0;    // 外部高速时钟没有旁路
    STM32_Rcc_Regs->cr.bit.HSERDY=0;    // 外部高速时钟就绪标志清零
        
    STM32_Rcc_Regs->cr.bit.HSEON=1;        // 外部高速时钟使能    1:HSE振荡器开启

    
     while( !(STM32_Rcc_Regs->cr.bit.HSERDY ) );//由硬件置1来指示外部时钟已经稳定。
     
     /* HCLK = SYSCLK=72MHZ  :HLCK 提供给CPU, 内存和DMA 最大72MHZ  */
     STM32_Rcc_Regs->crfgr.bit.HPRE=RCC_AHB_SYSCLK_DIV1_B;    //AHB预分频

    /* PCLK2 = HCLK/1=SYSCLK=72   PCLK2 提供给 APB2外设,最大72MHZ */
     STM32_Rcc_Regs->crfgr.bit.PPRE2=RCC_APB2_HCLK_DIV1_B;    //高速APB预分频(APB2)
     
     /* PCLK1 = HCLK/2=SYSCLK/2=36   PCLK1提供给APB1外设,最大36MHZ */
     STM32_Rcc_Regs->crfgr.bit.PPRE1=RCC_APB1_HCLK_DIV2_B;    //低速APB预分频(APB1)必须保证APB1时钟频率不超过36MHz

    
      /* ADCCLK = PCLK2/6     ADC转换速率:72M/6 = 12MHZ  */
     STM32_Rcc_Regs->cfgr.bit.ADCPRE=RCC_ADCPRE_PCLK2_DIV6_B;    
     
     /* Flash 2 wait state */
     STM32_Flash_Regs->ACR.all&=((u32)0x00000038);    //清零某些位
     STM32_Flash_Regs->ACR.bit.LATENCY=2;    
    STM32_Flash_Regs->ACR.bit.PRFTBE=1;        //预取缓冲区使能    

    /*  PLLCLK = 8MHz * 9 = 72MHZ ) */
     STM32_Rcc_Regs->cfgr.bit.PLLXTPRE=0;        //HSE分频器作为PLL输入  0:HSE不分频
     STM32_Rcc_Regs->cfgr.bit.PLLSRC=1;        //HSE时钟作为PLL输入时钟
     STM32_Rcc_Regs->cfgr.bit.PLLMUL=RCC_PLL_9_B;        //PLL倍频系数9

    /* Enable PLL */
    STM32_Rcc_Regs->cr.bit.PLLON=1;            // PLL使能    
    while( !(STM32_Rcc_Regs->cr.bit.PLLRDY ) );    // PLL时钟就绪标志    PLL锁定后由硬件置1

     /* Select PLL as system clock source */
     STM32_Rcc_Regs->cfgr.bit.SW=0;    
     STM32_Rcc_Regs->cfgr.bit.SW=2;        //RCC_SW_SYSCLK_PLL

    /* Wait till PLL is used as system clock source */    
     while(STM32_Rcc_Regs->cfgr.bit.SWS!=2);        //RCC_SWS_SYSCLK_PLL
            
    /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */
    STM32_Rcc_Regs->apb2enr.all |=(RCC_AFIOEN|RCC_IOPAEN|RCC_IOPBEN|RCC_IOPCEN|RCC_IOPDEN|RCC_IOPEEN);
    
    /* TIM2 AND CAN clocks enable */
    STM32_Rcc_Regs->apb1enr.all |=(RCC_TIM2EN| RCC_CANEN);    

}






此帖出自stm32/stm8论坛

最新回复

實在很高興!可以看到這麼好的知識!謝謝分享!!  详情 回复 发表于 2011-12-17 16:06
点赞 关注
 

回复
举报

76

帖子

0

TA的资源

一粒金砂(初级)

沙发
 

不错,这样做的好处是可以直接对寄存器编程

 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

板凳
 

STM32初学者笔记(6) 一步步建立自己的STM32函数

万利开发板 LCD DEMO 程序的函数,

//=========================================================================
//       Led_Config(void)
//=========================================================================
void STM32_Led_Config(void)
{
  
      /* Enable GPIOC clock */      
    STM32_Rcc_Regs->apb2enr.bit.IOPCEN=1;//IOPCEN:IO口C时钟使能    
    
      /* Configure PC.06, PC.07, PC.08 and PC.09 as output push-pull */
      // 注意了这个万利的注释是 PC.08 PC.09 而实在是PC.04 PC.05!
       
    STM32_Gpioc_Regs->crl.bit.CNF4=Output_push_pull;   // PC.04 推挽输出
    STM32_Gpioc_Regs->crl.bit.MODE4=Output_Mode_50mhz; // PC.04 输出模式,最大速度50MHz
  
    STM32_Gpioc_Regs->crl.bit.CNF5=Output_push_pull;   // PC.05 推挽输出
    STM32_Gpioc_Regs->crl.bit.MODE5=Output_Mode_50mhz; // PC.05 输出模式,最大速度50MHz

    STM32_Gpioc_Regs->crl.bit.CNF6=Output_push_pull;   // PC.06 推挽输出
    STM32_Gpioc_Regs->crl.bit.MODE6=Output_Mode_50mhz; // PC.06 输出模式,最大速度50MHz

    STM32_Gpioc_Regs->crl.bit.CNF7=Output_push_pull;   // PC.07 推挽输出
    STM32_Gpioc_Regs->crl.bit.MODE7=Output_Mode_50mhz; // PC.07 输出模式,最大速度50MHz
  
}

//=========================================================================
//       Button_Config(void)
//=========================================================================
void STM32_Button_Config(void)
{  
      /* Enable GPIOD clock */
    STM32_Rcc_Regs->apb2enr.bit.IOPDEN=1;//IOPCEN:IO口D时钟使能    

      /* Configure PD.03, PD.04 as output push-pull */
      // 注意了 这里是推挽输出 而实在是浮空输入!  
     STM32_Gpiod_Regs->crl.bit.CNF3=Input_floating;    // PD.03 浮空输入
    STM32_Gpiod_Regs->crl.bit.MODE3=Input_Mode;    // PD.03 输入模式
     STM32_Gpiod_Regs->crl.bit.CNF4=Input_floating;    // PD.04 浮空输入
    STM32_Gpiod_Regs->crl.bit.MODE4=Input_Mode;    // PD.04 输入模式
}

//=========================================================================
//      
//=========================================================================

      //GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource3);
      STM32_Afio_Regs->exticr0.bit.EXTI3=3;   //0011:EXTI3=PD[3]脚
      
        //GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource4);
        STM32_Afio_Regs->exticr1.bit.EXTI4=3;   //0011:EXTI4=PD[4]脚
        
此帖出自stm32/stm8论坛
 
 

回复

76

帖子

0

TA的资源

一粒金砂(初级)

4
 

STM32初学者笔记(7) 一步步建立自己的STM32函数

LCD DEMO  的MAIN() 主函数内的初始化

      //GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource3);
      STM32_Afio_Regs->exticr0.bit.EXTI3=3;   //0011:EXTI3=PD[3]脚
              
    
    /* Configure EXTI Line9 to generate an interrupt on falling edge */
        // 1:线x上的中断请求不被屏蔽  MR3=1中断请求不被屏蔽  ( EXTI 3 )    
        STM32_Exti_Regs->imr.bit.MR3=1;
        /* Clear Rising Falling edge configuration */
        // 0:禁止输入线x上的上升沿触发(中断和事件) tr3   ( EXTI 3 )
      STM32_Exti_Regs->rtsr.bit.TR3=0;      
        // 0:禁止输入线x上的下降沿触发(中断和事件) tr3  ( EXTI 3 )
        STM32_Exti_Regs->ftsr.bit.TR3=0;
        /* Select the trigger for the selected external interrupts */
        // 下降沿触发选择寄存器(EXTI_FTSR) 1:允许输入线x上的下降沿触发(中断和事件)
        STM32_Exti_Regs->ftsr.bit.TR3=1;    


        //GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource4);
        STM32_Afio_Regs->exticr1.bit.EXTI4=3;   //0011:EXTI4=PD[4]脚

      /* Configure EXTI Line9 to generate an interrupt on falling edge */
        // 1:线x上的中断请求不被屏蔽  MR4=1中断请求不被屏蔽  ( EXTI 4 )    
        STM32_Exti_Regs->imr.bit.MR4=1;
        /* Clear Rising Falling edge configuration */
        // 0:禁止输入线x上的上升沿触发(中断和事件) tr4   ( EXTI 4 )
      STM32_Exti_Regs->rtsr.bit.TR4=0;      
        // 0:禁止输入线x上的下降沿触发(中断和事件) tr4  ( EXTI 4 )
        STM32_Exti_Regs->ftsr.bit.TR4=0;
        /* Select the trigger for the selected external interrupts */
        // 下降沿触发选择寄存器(EXTI_FTSR) 1:允许输入线x上的下降沿触发(中断和事件)
        STM32_Exti_Regs->ftsr.bit.TR4=1;    

原函数内容如下:
/*
 GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource3);
  // Configure EXTI Line9 to generate an interrupt on falling edge 
  EXTI_InitStructure.EXTI_Line = EXTI_Line3;//((u32)0x00008) 
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//0
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//0x0C
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource4);
  // Configure EXTI Line9 to generate an interrupt on falling edge 
  EXTI_InitStructure.EXTI_Line = EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
*/
此帖出自stm32/stm8论坛
 
 
 

回复

62

帖子

0

TA的资源

一粒金砂(初级)

5
 

Cortex-m3 中断与嵌套 快速入门。

//====================================================
//    STM32 中断与嵌套NVIC 快速入门。
//     netjob  2008-8-1
//====================================================

我也是靠看这本书才弄懂的:

Cortex-M3 权威指南
Joseph Yiu 著
宋岩 译

其实很简单。

//CM3 有 最多240个中断(通常外部中断写作IRQs),就是 软件上说的 IRQ CHANAELx(中断通道号x)
每个中断有自己的可编程的中断优先级【 有唯一对应的 中断优先级寄存器 】.

由于CM3支持 硬件中断嵌套,所以可以有 256 级的可编程优先级
和 256级中断嵌套【 书上称:抢占(preempt) 优先级】
所以大家可以设:
IRQ CHANAEL 0 通道 = 2    中断优先级    WWDG 窗口定时器中断
IRQ CHANAEL 1 通道 = 0    中断优先级    PVD 联到EXTI的电源电压检测(PVD)中断
IRQ CHANAEL 3 通道 = 255  中断优先级    RTC 实时时钟(RTC)全局中断
IRQ CHANAEL 6 通道 = 10   中断优先级    EXTI0 EXTI线0中断
.....
IRQ CHANAEL 239 通道 =  (0<x<255)   中断优先级    ..


这个实在是太恐怖了! 是的,其实CM3 并没有这样做。
实在的芯片例如STM32等就只有设计来可用才64级可编程优先级和8级中断嵌套。

对 64级中断就是说:( INT0 到 INT63)这个大家比较好理解,其它的64···239就不用了。
IRQ CHANAEL 0 
。。。
IRQ CHANAEL  63

而8级中断嵌套这又是何解呢?
是这样的,上面说 一个 【中断】对应 一个【中断优先级寄存器】,而这个寄存器是 8 位的。
当然就是 256级了。而现在就用了 它其中的 BIT7,IT6,BIT5 三位来表示,而且是MSB对齐的。

用了3 个位来表达优先级(MSB 对齐的我们能够使用的8 个优先级为:0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)
这样我们在【中断优先级寄存器】就不能按理论的填 0到255之间的数了,
而只能填0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)

所以大家可以设:
IRQ CHANAEL 0 通道 = 0x20  中断优先级    WWDG 窗口定时器中断
IRQ CHANAEL 1 通道 = 0x40  中断优先级    PVD 联到EXTI的电源电压检测(PVD)中断
IRQ CHANAEL 3 通道 = 0x20  中断优先级    RTC 实时时钟(RTC)全局中断
IRQ CHANAEL 6 通道 = 0xA0  中断优先级    EXTI0 EXTI线0中断
.....
IRQ CHANAEL 63 通道 =  【0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)】

大家注意到了,上面通道0和通道3 的优先级都是0X20, 这怎么办?
// 如果优先级完全相同的多个异常同时悬起,则先响应异常编号最小的那一个。如IRQ #0会比IRQ #3 先得到响应

而且文中还讲了 【优先级分组】,这又是什么回事?

其实我回头看来,这个【优先级分组】和【抢占优先级】【亚优先级】都毫无意义的。 
如果当时用 256级即是 把【中断优先级寄存器】的8位都全用上,就没这个必要了。还什么优先级分组呢!
就是因为厂家现在【偷工减料】,才搞出这个明堂来的。

是这样的,在 应用程序中断及复位控制寄存器(AIRCR) 中的 10:8 位【3位】是表示【优先级分组】
它作用主要是 用于对【中断优先级寄存器】『我们现在中用了BIT7,BIT6,BIT5三位』的功能的说明。
有一个表,在《Cortex-M3 权威指南》的110页, 例如我们把AIRCR的10:8 位设为【5】 ,
查表可得【抢占优先级】=【7:6】,【亚优先级】=【5:0】,

对于【中断优先级寄存器】只用了BIT7,6,5, 因此我们可以看作是 【7:6】,【5】。那4-0 可以不管。

现在我们的 IRQ0=0X20, IRQ3=0X20, 也就是  【0 0 1 0  】『 bit7=0,bit6=0,bit5=1,bit4=0』
因为大家(IRQ0/IRQ3)的 【抢占优先级】=【7:6】都是0, 说明它们的中断相应级别是一样的。
再继续判断它们哪个更优先的责任就要看【5】,结果连【5】都是一样的!
那就按默认:
// 如果优先级完全相同的多个异常同时悬起,则先响应异常编号最小的那一个。如IRQ #0会比IRQ #3 先得到响应

由于CM3没有 进中断【关全局中断相应】这事,只要是中断通道打开了,就会存在 通道间的 嵌套,即是会发生
【抢占】的情况了。


上面就简短的说明,如果要详细理解,可以看《Cortex-M3 权威指南》。
有任何理解不当,请各位多多指教!

此帖出自stm32/stm8论坛
 
 
 

回复

78

帖子

0

TA的资源

一粒金砂(初级)

6
 

学习中

                                  
此帖出自stm32/stm8论坛
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

7
 

顶!

“2)抢占式优先级别相同的中断源之间没有嵌套关系;” 

所以大家可以设:
IRQ CHANAEL 0 通道 = 0x20  中断优先级    WWDG 窗口定时器中断
IRQ CHANAEL 1 通道 = 0x40  中断优先级    PVD 联到EXTI的电源电压检测(PVD)中断
IRQ CHANAEL 3 通道 = 0x20  中断优先级    RTC 实时时钟(RTC)全局中断
IRQ CHANAEL 6 通道 = 0xA0  中断优先级    EXTI0 EXTI线0中断

这样 0 通道和3 通道就不会有嵌套情况,而是0 通道按默认比3 通道优先高些。

而0 通道与1 通道就会有嵌套情况。 
 
芯片复位后,默认的优先级分组 是 0, 就是 【7:1】表示抢占式优先级,【0】表示亚优先级,

这样对于MSB对齐的 8 个优先级为:0x00(最高),0x20,0x40,0x60,0x80,0xA0,0xC0 以及0xE0。)
使用就很方便了,建议大家就用默认的默认的优先级分组 是 0,也就是复位后的值,哈哈!


例如下面的两个按键,都使用外中断方式, 使用了PD.3,和PD.4两个引脚。这两个中断的优先级都是0X20,
按默认的优先级分组,它们之间不会发生中断嵌套。

        /* Enable the EXTI3 Interrupt on PD.3 */
    STM32_Nvic_Regs->Priority[9].all=0x20;   // 中断的优先级是 0X20
    STM32_Nvic_Regs->Enable[0].bit.INT9=1;  // 开INT9 中断   IRQ9 

        /* Enable the EXTI4 Interrupt on PD.4 */
    STM32_Nvic_Regs->Priority[10].all=0x20;  // 中断的优先级是 0X20 
    STM32_Nvic_Regs->Enable[0].bit.INT10=1; // 开INT10 中断  IRQ10 


此帖出自stm32/stm8论坛
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

8
 

关于STM32库, 这里改为如下是否更好些?

关于STM32库, 这里改为如下是否更好些? 


原STM32
typedef struct
{
  vu32 Enable[2];
  u32 RESERVED0[30];
  vu32 Disable[2];
  u32 RSERVED1[30];
  vu32 Set[2];
  u32 RESERVED2[30];
  vu32 Clear[2];
  u32 RESERVED3[30];
  vu32 Active[2];
  u32 RESERVED4[62];
  vu32 Priority[11];
} NVIC_TypeDef;


struct NVIC_REGS {
   union  NVIC_SETENA_REG     Enable[2];    
   u32    Reserved0[30]                ;
   union  NVIC_CLRENA_REG     Disable[2];   
   u32    Reserved1[30]              ;
   union  NVIC_SETPEND_REG       Set[2] ;   
   u32    Reserved2[30]                ;
   union  NVIC_CLRPEND_REG       Clear[2];  
   u32    Reserved3[30]                ;
   union  NVIC_ACTIVE_REG       Active[2];  
   u32    Reserved4[62]                ;
   u8 NVIC_Priority_REG     Priority[256]; // 字节宽度。外中断[0] 到外中断[239]的优先级

};
这是因为一个外中断对应一个中断优先级寄存器,是8位的。这样更形象
这样更直观些,例如可以这样设INT【10】的中断优先级和开中断。
     /* Enable the EXTI4 Interrupt on PD.4 */
STM32_Nvic_Regs->Priority[10].all=0x20;
STM32_Nvic_Regs->Enable[0].bit.INT10=1;   // IRQ10  默认PRI=17 可设置 EXTI4 EXTI线4中断 0x0000_0068
 
 
 STM32库 好多地方都 【似是而非的】。 

例如这个:
  vu32 Priority[11];

明明是一个中断对应一个8位的优先级寄存器的,非要写 32位的【11】个数组。
如果按客观事实,STM32只有64个外中断,而不是CORTEX-M3核所说的239个,
写为: uint8  Priority[64];比较合适。
 
 
此帖出自stm32/stm8论坛
 
 
 

回复

63

帖子

0

TA的资源

一粒金砂(初级)

9
 

STM32初学者笔记(8) 一步步建立自己的STM32函数

//=========================================================================
//void RTC_Configuration(void)
//=========================================================================
void STM32_RTC_Configuration(void)
{
      /* Enable PWR and BKP clocks */
      //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
      STM32_Rcc_Regs->apb1enr.all |=(RCC_PWREN| RCC_BKPEN);    

      /* Allow access to BKP Domain */
      //PWR_BackupAccessCmd(ENABLE);  
      STM32_Pwr_Regs->cr.bit.DBP=1;    //DBP:取消后备区域的写保护 
   
      /* Reset Backup Domain */
      //BKP_DeInit();
    STM32_Rcc_Regs->bdcr.bit.BDRST=1;//1:复位整个备份域
    STM32_Rcc_Regs->bdcr.bit.BDRST=0;


      /* Enable LSE */
      //RCC_LSEConfig(RCC_LSE_ON);
    STM32_Rcc_Regs->bdcr.bit.LSEON=0;    // Reset LSEON bit 
    STM32_Rcc_Regs->bdcr.bit.LSERDY=0;    // Reset LSEBYP bit
    STM32_Rcc_Regs->bdcr.bit.LSEON=1;    // 外部低速振荡器使能    
    
          
      /* Wait till LSE is ready */
      //while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
    while( !(STM32_Rcc_Regs->bdcr.bit.LSERDY ) );//由硬件置1来指示外部时钟已经稳定。

      
      /* Select LSE as RTC Clock Source */
      //RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    STM32_Rcc_Regs->bdcr.bit.RTCSEL=1;    // RCC_RTCCLK_LSE
    
      /* Enable RTC Clock */
      //RCC_RTCCLKCmd(ENABLE);
      STM32_Rcc_Regs->bdcr.bit.RTCEN=1;    // RTC时钟使能

      /* Wait for RTC registers synchronization */
      //RTC_WaitForSynchro();
    TM32_Rtc_Regs->crl.bit.RSF=0;// 待RTC_CRL 寄存器中的RSF 位(寄存器同步标志)被硬件置1。
    while( !(TM32_Rtc_Regs->crl.bit.RSF ) );
    
      /* Wait until last write operation on RTC registers has finished */
      //RTC_WaitForLastTask();
      // 软件来查询在前一次写操作结束来判断RTC 寄存器是否处于更新中。仅当RTOFF 状态位是“1"时,RTC 寄存器可以写入新的值。
      while( !(TM32_Rtc_Regs->crl.bit.RTOFF ) );

      /* Enable the RTC Second */
      //RTC_ITConfig(RTC_IT_SEC, ENABLE);
      TM32_Rtc_Regs->crl.bit.SECIE=1;    //允许秒中断

      /* Wait until last write operation on RTC registers has finished */
      //RTC_WaitForLastTask();
      while( !(TM32_Rtc_Regs->crl.bit.RTOFF ) );//等待写操作结束
      

      /* Set RTC prescaler: set RTC period to 1sec */
      //RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
      TM32_Rtc_Regs->crl.bit.CNF=1;// RTC进入配置模式
      TM32_Rtc_Regs->prlh.all=((u32)32767 & ((u32)0x000F0000))>>16; // 32767 的bit16-19
      TM32_Rtc_Regs->prll.all=(u32)32767 &  ((u32)0x0000FFFF);      // 32767 的bit0-15
      TM32_Rtc_Regs->crl.bit.CNF=0;// RTC退出配置模式      
      
      /* Wait until last write operation on RTC registers has finished */
      //RTC_WaitForLastTask();
      while( !(TM32_Rtc_Regs->crl.bit.RTOFF ) );//等待写操作结束
      
      
}
此帖出自stm32/stm8论坛
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

10
 

STM32初学者笔记(8) 一步步建立自己的STM32函数


是STM32库函数本身问题,有可能把LSE旁路了!
更正:

/* Enable LSE */
      //RCC_LSEConfig(RCC_LSE_ON);
    STM32_Rcc_Regs->bdcr.bit.LSEON=0;    // Reset LSEON bit 
    STM32_Rcc_Regs->bdcr.bit.LSEBYP=0;    // Reset LSEBYP bit
    STM32_Rcc_Regs->bdcr.bit.LSEON=1;    // 外部低速振荡器使能    
此帖出自stm32/stm8论坛
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

11
 

STM32初学者笔记(9) 一步步建立自己的STM32函数

定时器的简单使用例子:

//=========================================================================
//    TIM_Configuration(void)
//      设置TIMER-2定时器 为计数溢出中断,1毫秒中断一次
//    TIM2、3、4的时钟源是 APB1 即是 PCLK1  ( APB1 对应 PCLK1 )
//    PCLK1 = APB1 = HCLK/2 = SYSCLK/2 = 36MHZ (36,000,000 HZ)
//=========================================================================

void STM32_TIM_Configuration(void)

      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    //  TIM_OCInitTypeDef  TIM_OCInitStructure ;
      //TIM_DeInit( TIM2);//复位TIM2定时器      
      STM32_Rcc_Regs->apb1rstr.all |=  RCC_TIM2RST;
      STM32_Rcc_Regs->apb1rstr.all &= ~RCC_TIM2RST;
                  
      /* TIM2 configuration */
      //TIM_TimeBaseStructure.TIM_Period = 1000;      //  定时1毫秒
      //TIM_TimeBaseStructure.TIM_Prescaler = 36;     //  36分频
      //TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; // 时钟分割  
      //TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //计数方向向上计数
      //TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    STM32_Tim2_Regs->arr.all=1000;  //  定时1毫秒
    STM32_Tim2_Regs->psc.all=36;    //  36分频
    STM32_Tim2_Regs->cr1.bit.CKD=0; //  时钟分频因子
    STM32_Tim2_Regs->cr1.bit.DIR=0; //  0:计数器向上计数

      /* Clear TIM2 update pending flag[清除TIM2溢出中断标志] */
      //TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    STM32_Tim2_Regs->sr.bit.UIF=0;    //    更新中断标记 由软件清0 ,例如当上溢或下溢时,软件对CNT重新初始化
          

      /* Enable TIM2 Update interrupt [TIM2溢出中断允许]*/
      //TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  
      STM32_Tim2_Regs->dier.bit.UIE=1;//    允许更新中断
      
      /* TIM2 enable counter [允许tim2计数]*/
      //TIM_Cmd(TIM2, ENABLE);
      STM32_Tim2_Regs->cr1.bit.CEN=1;//    开启计数器
      
此帖出自stm32/stm8论坛
 
 
 

回复

59

帖子

0

TA的资源

一粒金砂(初级)

12
 

36MHz36分频

                                 计数1000能1ms?
此帖出自stm32/stm8论坛
 
 
 

回复

67

帖子

0

TA的资源

一粒金砂(初级)

13
 

一步步来吧!大家刚开始都是菜鸟啊!

                                  
此帖出自stm32/stm8论坛
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

14
 

STM32初学者笔记(10) 一步步建立自己的STM32函数

//=========================================================================
//    ADC_Configuration(void)
//=========================================================================
void  STM32_ADC_Configuration(void)
{
    
    int ADC_ConvertedValue=0;
    
    //GPIO_InitTypeDef GPIO_InitStructure;
                                          
      /* Configure PC.01 and PC.04 (ADC Channel11 and Channel14) as analog input */
      //GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4;//((u16)0x0010)
      //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//GPIO_Mode_AIN = 0x0,
    //GPIO_Init(GPIOC, &GPIO_InitStructure);

    STM32_Gpioc_Regs->crl.bit.CNF1=Analog_Input;    // PC.01 模拟输入 ADC Channel11
    STM32_Gpioc_Regs->crl.bit.MODE1=Input_Mode;    // PC.01 输入模式

    STM32_Gpioc_Regs->crl.bit.CNF4=Analog_Input;    // PC.04 模拟输入 ADCChannel14
    STM32_Gpioc_Regs->crl.bit.MODE4=Input_Mode;    // PC.04 输入模式


    /* Enable ADC1 clock */
      //RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
      STM32_Rcc_Regs->apb2enr.bit.ADC1EN=1;   // ADC1EN:ADC1时钟使能
      
      
      /* Set the ADC Clock Divider */
      //RCC_ADCCLKConfig(RCC_PCLK2_Div2); 
      /* ADCCLK = PCLK2/2     ADC转换速率:72M/2 = 36MHZ  */
     STM32_Rcc_Regs->cfgr.bit.ADCPRE=RCC_ADCPRE_PCLK2_DIV2_B;    

    /* reset the adc */
    // ADC_DeInit(ADC1); 
      STM32_Rcc_Regs->apb2rstr.all |=  RCC_ADC1RST;
      STM32_Rcc_Regs->apb2rstr.all &= ~RCC_ADC1RST;


    //ADC_InitStructure.ADC_Mode = ADC_Mode_Independent  ;
    //ADC_InitStructure.ADC_ScanConvMode = DISABLE  ;
    //ADC_InitStructure.ADC_ContinuousConvMode = ENABLE  ;
    //ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None  ;
    //ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right  ;
    //ADC_InitStructure.ADC_NbrOfChannel = 2;
      //ADC_Init(ADC1, &ADC_InitStructure);
            
      STM32_Adc1_Regs->cr1.bit.DUALMOD=0;    //0000:独立模式 ADC_Mode_Independent
      STM32_Adc1_Regs->cr1.bit.SCAN=0;       //0:   关闭扫描模式 ADC_ScanConvMode = DISABLE
      
      STM32_Adc1_Regs->cr2.bit.CONTL=0;    //0:单次转换模式
      STM32_Adc1_Regs->cr2.bit.CONTL=1;    //1:连续转换模式  ContinuousConvMode = ENABLE
      STM32_Adc1_Regs->cr2.bit.EXTTRIG=0;       //0:不用外部触发信号启动转换 ADC_ExternalTrigConv_None
      STM32_Adc1_Regs->cr2.bit.ALIGN=0;       //0:数据右对齐 ADC_DataAlign_Right      
    STM32_Adc1_Regs->sqr1.bit.L=1;       //   规则通道序列长度  0001:2个转换 ADC_NbrOfChannel = 2
    
                          
      /* ADC1 regular channel11/14 configuration */
      // ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);
    // ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 2, ADC_SampleTime_55Cycles5);
    
    STM32_Adc1_Regs->sqr3.bit.SQ1=11;            // 规则序列中的第1个转换=ADC Channel11    
    STM32_Adc1_Regs->smpr1.bit.SMP11=_SampleTime_55Cycles5;    // 通道11 的采样时间55.5周期
    
    STM32_Adc1_Regs->sqr3.bit.SQ2=14;            // 规则序列中的第2个转换=ADC Channel14
    STM32_Adc1_Regs->smpr1.bit.SMP14=_SampleTime_55Cycles5;    // 通道14 的采样时间55.5周期
    

      /* Enable ADC1 DMA */
    //  ADC_DMACmd(ADC1, ENABLE);

      /* Enable ADC1 */
      //ADC_Cmd(ADC1, ENABLE);
      STM32_Adc1_Regs->cr2.bit.ADON=1;   //1:开启ADC并启动转换 当第一次设置ADON 位时,它将ADC 从断电状态下唤醒
      ADC_ConvertedValue=ADC_ConvertedValue;
      ADC_ConvertedValue=ADC_ConvertedValue;
      STM32_Adc1_Regs->cr2.bit.ADON=1;   //ADC 上电延迟一段时间后(tSTAB),再次设置ADON 位时开始进行转换。
      

      /* Enable ADC1 reset calibaration register */
      //ADC_ResetCalibration(ADC1);
      STM32_Adc1_Regs->cr2.bit.RSTCAL=1;   //复位校准 0:校准寄存器已初始化 1:初始化校准寄存器
      
      /* Check the end of ADC1 reset calibration register */
      //while(ADC_GetResetCalibrationStatus(ADC1);
      while( !STM32_Adc1_Regs->cr2.bit.RSTCAL );//该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
            
      /* Start ADC1 calibaration */
      //ADC_StartCalibration(ADC1);
      STM32_Adc1_Regs->cr2.bit.CAL=1;   //A/D校准    0:校准完成    1:开始校准
            
      /* Check the end of ADC1 calibration */
      //while(ADC_GetCalibrationStatus(ADC1));
      while(!STM32_Adc1_Regs->cr2.bit.CAL);//该位由软件设置以开始校准,并在校准结束时由硬件清除
            
      /* Start ADC1 Software Conversion */
      //ADC_SoftwareStartConvCmd(ADC1, ENABLE); 
    STM32_Adc1_Regs->cr2.bit.SWSTART=1;// 开始转换规则通道(连续转换模式) ;设置ADC_CR2寄存器的ADON位,启动一组规则通道的转换?
      
    while (0)
        {
            //while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
            while(!STM32_Adc1_Regs->sr.bit.EOC);//转换结束位  0:转换未完成 1:转换完成
                                    
            /* Get the conversion value */
           //ADC_ConvertedValue = ADC_GetConversionValue(ADC1);
           //ADC_ConvertedValue = (ADC1->DR);
           ADC_ConvertedValue =STM32_Adc1_Regs->dr.all;           
                                 
            /* Clear the end of conversion flag */
            //ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
            STM32_Adc1_Regs->sr.bit.EOC=0;// 上面读DR,就自动清零这位了!            
        }
          
}//end sub
此帖出自stm32/stm8论坛
 
 
 

回复

81

帖子

0

TA的资源

一粒金砂(初级)

15
 

学习~~

                                  
此帖出自stm32/stm8论坛
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

16
 

STM32初学者笔记(11) 一步步建立自己的STM32函数

//=========================================================================
//    ADC_Configuration(void)
//=========================================================================
void STM32_I2C_Configuration(void)
{
      //GPIO_InitTypeDef  GPIO_InitStructure;
      //I2C_InitTypeDef   I2C_InitStructure;

      /* GPIOB Periph clock enable */
      //RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
      STM32_Rcc_Regs->apb2enr.all|=(RCC_IOPBEN|RCC_AFIOEN);   // 时钟使能
  
      /* I2C1 Periph clock enable */
      //RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    //STM32_Rcc_Regs->apb1enr.bit.all|=RCC_I2C1EN;   // I2C1时钟使能
    STM32_Rcc_Regs->apb1enr.bit.I2C1EN=1;        // I2C1时钟使能
    
      /* Configure I2C1 pins: SCL and SDA */
      //GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
      //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;// 复用功能开漏输出模式
      //GPIO_Init(GPIOB, &GPIO_InitStructure);


    STM32_Gpiob_Regs->crl.bit.CNF6=Output_Af_open_drain;    // PB.06 复用功能开漏输出模式
    STM32_Gpiob_Regs->crl.bit.MODE6=Output_Mode_50mhz;    // PB.06  SCL

    STM32_Gpiob_Regs->crl.bit.CNF7=Output_Af_open_drain;    // PB.07 复用功能开漏输出模式
    STM32_Gpiob_Regs->crl.bit.MODE7=Output_Mode_50mhz;    // PB.07  SDA

      //I2C_DeInit(I2C1);
      STM32_Rcc_Regs->apb1rstr.all |=  RCC_I2C1RST;
      STM32_Rcc_Regs->apb1rstr.all &= ~RCC_I2C1RST;

      /* I2C1 Init */
    //  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;        //((u16)0x0000)
    //  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;    //((u16)0xBFFF)
    //  I2C_InitStructure.I2C_OwnAddress1 = 0x00;         // A1,A0
    //  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;        //((u16)0x0400)
    //  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//((u16)0x4000)
    //  I2C_InitStructure.I2C_ClockSpeed = 200000;         //200KHZ
    //  I2C_Init(I2C1, &I2C_InitStructure);      
      
    STM32_I2c1_Regs->cr2.bit.FREQ=36;//        PCLK1=36MHZ; 27.77ns
    STM32_I2c1_Regs->cr1.bit.PE=0;   //        0:禁用I2C外设(注:只有当I2C被禁用(PE=0)时,才能设置TRISE[5:0])
    STM32_I2c1_Regs->ccr.bit.FS=1;    //       1:快速模式的I2C   SCL上升时间为300ns
    STM32_I2c1_Regs->ccr.bit.DUTY=0;//       快速模式时的占空比    0:快速模式下:Tlow/Thigh = 2
    STM32_I2c1_Regs->trise.all=12;    //        300ns/(100/36)+1 最大上升时间
    STM32_I2c1_Regs->ccr.bit.CCR=60;//        分频系数 36MHZ/(200KHZ*(2+1));  因为:(Tlow/Thigh = 2)
    STM32_I2c1_Regs->cr1.bit.PE=1;   //        1:启用I2C外设
    
    STM32_I2c1_Regs->cr1.bit.SMBUS=0;//      0:I2C模式
    STM32_I2c1_Regs->cr1.bit.SMBTYPE=0;//      
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
        
    STM32_I2c1_Regs->oar1.bit.BITSET=1;  //      必须设置并保持为1
    STM32_I2c1_Regs->oar1.bit.ADDMODE=0; //   7位从地址
            
      /* I2C1 Init */
      //I2C_Cmd(I2C1, ENABLE);
      STM32_I2c1_Regs->cr1.bit.PE=1;   //        1:启用I2C外设
      

}//end sub
此帖出自stm32/stm8论坛
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

17
 

是否继续把这贴倒塌下去呢?

                                 倒塌STM32库,但在这过程中,反而对STM32库了解更深了!
此帖出自stm32/stm8论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

18
 

STM32初学者笔记(12) 一步步建立自己的STM32函数

I2C的函数,初步。

//==========================================================================//
//    
//    如果ChipID的LSB=0 是读,LSB=1是写,
//==========================================================================//
void SetCurrentAddress(unsigned char ChipID, unsigned short Address) 
{
         STM32_I2c1_Regs->cr1.bit.PE=0;   //        0:禁用I2C外设 ,同时硬件清零某些标志位
         STM32_I2c1_Regs->cr1.bit.PE=0;   //        0:禁用I2C外设 ,同时硬件清零某些标志位                 
       STM32_I2c1_Regs->cr1.bit.PE=1;     //      1:启用I2C外设
       STM32_I2c1_Regs->cr1.bit.PE=1;     //      1:启用I2C外设
    
    //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
      
    //I2C_GenerateSTART(I2C1, ENABLE);//START=1        
    STM32_I2c1_Regs->cr1.all|= I2C_EN|I2C_START;
                          
    /* Test on I2C1 EV5 and clear it */
      // 【SB=1 起始条件已发送 读SR1,然后写数据DR 清零 】   MSL=1主模式   BUSY=1 在总线上正在进行数据通讯 )
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  /* EV5 */
  
      /* Send slave address for write */
      //I2C_Send7bitAddress(I2C1, ChipID, I2C_Direction_Transmitter); //I2Cx->DR = Addr;
      STM32_I2c1_Regs->dr.all=ChipID;
    
    // 【ADDR=1  地址发送结束;读SR1和SR2来清零 】。  TXE=1 数据寄存器空 MSL=1 BUSY=1, TRA=1 数据已发送
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* EV6 ((u32)0x00070082)  1: 地址发送结束 */
  
      /* Send the low part of memory address */
    //I2C_SendData(I2C1, (u8)nAddr);//I2Cx->DR = nAddr;
    STM32_I2c1_Regs->dr.all=(u8)Address;
    
      /* Test on I2C1 EV8 and clear it */
      // 【TXE=1 数据寄存器空; 写数据DR清除,START,STOP】  BTF=1: 字节发送结束 TRA=数据已发送  BUSY=在总线上正在进行数据通讯  MSL=主模式
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /* EV8 ((u32)0x00070084)   TRA, BUSY, MSL, TXE and BTF flags */ 
}//END SetCurrentAddress


//==========================================================================//

void SendI2CAck(void)
{
      //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)  
}//end
//==========================================================================//
void SendI2CNAck(void)
{
      //I2C_AcknowledgeConfig(I2C1, DISABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=0;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
}//end
//==========================================================================
//
//==========================================================================
void StartI2C(void)
{
         STM32_I2c1_Regs->cr1.bit.PE=0;   //        0:禁用I2C外设 ,同时硬件清零某些标志位
         STM32_I2c1_Regs->cr1.bit.PE=0;   //        0:禁用I2C外设 ,同时硬件清零某些标志位                 
       STM32_I2c1_Regs->cr1.bit.PE=1;     //      1:启用I2C外设
       STM32_I2c1_Regs->cr1.bit.PE=1;     //      1:启用I2C外设
    //I2C_GenerateSTART(I2C1, ENABLE);// START=1            
    STM32_I2c1_Regs->cr1.all|= I2C_EN|I2C_START;
                          
    /* Test on I2C1 EV5 and clear it */      
      // 【SB=1 起始条件已发送 ; 读SR1,然后写数据DR 清零 】   MSL=1主模式   BUSY=1 在总线上正在进行数据通讯 )
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));  /* EV5 */

}//end sub
//==========================================================================
//
//==========================================================================
void StopI2C(void)
{            
    /* Send I2C1 STOP Condition */
          //I2C_GenerateSTOP(I2C1, ENABLE);        
    STM32_I2c1_Regs->cr1.all|= I2C_EN|I2C_STOP;
        while(STM32_I2c1_Regs->sr2.bit.MSL);  //  0:从模式 

}//end sub
//==========================================================================
//
//==========================================================================
void SendAByte(uint8 data)
{
    /* Send I2C1 data */
        //I2C_SendData(I2C1, pDat);
    STM32_I2c1_Regs->dr.all=data;    
      //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
        /* Test on I2C1 EV8 and clear it */
      // 【TXE=1 数据寄存器空; 写数据DR清除,START,STOP】  BTF=1: 字节发送结束 TRA=数据已发送  BUSY=在总线上正在进行数据通讯  MSL=主模式      
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /* EV8 ((u32)0x00070084)   TRA, BUSY, MSL, TXE and BTF flags */         
}//end sub

//==========================================================================
//
//==========================================================================
uint8 ReadAByte_ACK(void)
{
      uint8 data=0;
      //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)    
    /* Test on EV7 and clear it */
    // 【RXNE=1  数据寄存器非空; 读写DR清零 】 BUSY=1 在总线上正在进行数据通讯 MSL=1 主模式
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));  /* EV7  ((u32)0x00030040)   BUSY, MSL and RXNE flags */        
    data = STM32_I2c1_Regs->dr.all;              
      return(data);

}//end sub
//==========================================================================
//
//==========================================================================
uint8 ReadAByte_NOACK(void)
{
      uint8 data=0;

      //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=0;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
    
    /* Test on EV7 and clear it */
    // 【RXNE=1  数据寄存器非空; 读写DR清零 】 BUSY=1 在总线上正在进行数据通讯 MSL=1 主模式
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));/* EV7  ((u32)0x00030040)   BUSY, MSL and RXNE flags */
    
    data = STM32_I2c1_Regs->dr.all;              
      return(data);
      
}//end sub
// 只写低8位
//==========================================================================
//
//==========================================================================

void WriteAByte(uint8 data)
{
      //I2C_AcknowledgeConfig(I2C1, ENABLE);//ACK=1;
    STM32_I2c1_Regs->cr1.bit.ACK=1;   //      ACK:应答使能    1:在接收到一个字节后返回一个应答(匹配的地址或数据)
    STM32_I2c1_Regs->dr.all=data;              
    /* Test on I2C1 EV8 and clear it */
      // 【TXE=1 数据寄存器空 ;写数据DR清除,START,STOP】  BTF=1: 字节发送结束 TRA=数据已发送  BUSY=在总线上正在进行数据通讯  MSL=主模式      
      while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/* EV8 ((u32)0x00070084)   TRA, BUSY, MSL, TXE and BTF flags */ 
            
}//end sub
此帖出自stm32/stm8论坛
 
 
 

回复

88

帖子

0

TA的资源

一粒金砂(初级)

19
 

汗! 这个程序很罗说啊!

                                  
此帖出自stm32/stm8论坛
 
 
 

回复

64

帖子

0

TA的资源

一粒金砂(初级)

20
 

STM32的I2C设计不合看法

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表