打印
[STM8]

STM8L相关功能配置

[复制链接]
777|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
最近搞了搞STM8L系列的板子,感觉有些地方和S系列的不太一样,简单总结了相关外设的配置方法,相关的驱动都是可以运行的,详细内容如下

RCC时钟




概述:

系统时钟有四个时钟源,高速外部,高速内部,低速外部,低速内部,
上电系统默认的时钟源为高速内部时钟,时钟频率为
2M(16M/8).

  HSI
  :
  16M
高速内部
RC
振荡器

  HSE :
  1-16M
高速外部晶体振荡器

  LSE
  :
  32.768K
低速外部晶体振荡器

  LSI
   :
  38K
低速内部振荡器



使用特权

评论回复
沙发
guanjiaer|  楼主 | 2021-6-4 19:56 | 只看该作者
STM8L CLOCK寄存器:

时钟分频寄存器
  :
  CLK_CKDIVR
  (
系统时钟的分频系数设置
)

实时时钟寄存器
  :
  CLK_CRTCR  
  (RTC
时钟源及分频系数,
RTC
忙状态
)

内部时钟寄存器
  :
  CLK_ICKCR   
  (
内部时钟开关及状态
)

二个外设时钟门控寄存器
  :
  CLK_PCKENR1/CLK_PCKENR2
(
相关外设的时钟开关
)

  CCO
寄存器
  :
  CLK_CCOR
  (
时钟输出
)         

外部时钟寄存器
  :
  CLK_ECKCR
(
外部时钟开关及状态
)

系统时钟状态寄存器
  :
  CLK_SCSR
(
系统时钟源选择
)


系统时钟切换寄存器
  :
  CLK_SWR
(
系统时钟源切换
)

切换控制寄存器
  :
  CLK_SWCR      

  CSS
寄存器
  :
  CLK_CSSR
(
时钟安全系统
)

蜂鸣器时钟寄存器
  :
  CLK_CBEEPR (
时钟源选择及切换忙状态
)

  HSI
校准寄存器
  :
  CLK_HSICALR

  HSI
时钟校准微调寄存器
  :
  CLK_HSITRIMR

  HSI
解锁寄存器
  :
  CLK_HSIUNLCKR

主调节器控制状态寄存器

:

CLK_REGCSR
(时钟源的开启状态)


使用特权

评论回复
板凳
guanjiaer|  楼主 | 2021-6-4 20:10 | 只看该作者
系统时钟分频系数,默认值为
0x03(8
分频
)
,即默认值为
2M(16M/8)




每个外设有相应的时钟开关,与
stm32
一样,在使用相应外设之前要打开时钟,寄存器为
CLK_PCKENR1

CLK_PCKENR2




  




时钟源选择,我们可以使用默认值选择高速内部时钟



使用特权

评论回复
地板
guanjiaer|  楼主 | 2021-6-4 20:10 | 只看该作者
void InitSystemClock( void )

{

     CLK_CKDIVR = 0x00;//
系统时钟分频

  /*
打开全部的外设时钟*/

CLK_PCKENR1 |= 0xff;

CLK_PCKENR2 |= 0xff;

}


STM8L STM8S 的时钟部分没有太大的区别,需要注意的就是 STM8L 的外设时钟是关闭的(为了降低功耗),而 STM8S 的外设时钟是打开的,这个大家看一下相关寄存器的复位值就可以了,因此在使用 stm8l 的时候要记得打开相应的外设时钟



使用特权

评论回复
5
guanjiaer|  楼主 | 2021-6-4 20:11 | 只看该作者
GPIO

  IO
的配置比较简单,
STM8L

STM8S
没有什么区别,总共也就那么几个寄存器

  STM8L GPIO
寄存器

一个数据方向寄存器
  :
  Px_DDR

一个输出数据寄存器
  :
  Px_ODR

一个输入寄存器
  :
  Px_IDR

二个控制寄存器
  :
  Px_CR1/Px_CR2

可选择的输入模式:浮动输入和带上拉输入

可选择的输出模式:推挽式输出

关于复用功能,
IO口寄存器中没有特定的给出,我们在用到相关复用功能时,在相应外设中进行设置

  端口输出寄存器


端口输入寄存器


端口方向寄存器



使用特权

评论回复
6
guanjiaer|  楼主 | 2021-6-4 20:12 | 只看该作者
配置 IO的时候要注意一下下面这两个寄存器,CR1主要选择输入输出的相应模式,CR2配置输出速度, 要注意一下在适应外部中断的时候,相应的 IO口的CR2要开启外部中断




   

   

使用特权

评论回复
7
guanjiaer|  楼主 | 2021-6-4 20:12 | 只看该作者
void GPIOConfigure(void)

{

      /*LED

(
用作
pwm
呼吸灯配置输入模式
)*/

PE_DDR &= ~0X80;

   PE_CR1 |= 0X80;

PE_CR2 |= 0X00;





#if 0

      /*UART
  硬件串口可以不用配置
*/

      PC_DDR |= 0X08; //
输出
TX---PC3

      PC_ODR |= 0X08; //
拉高置
1

      PC_CR1 |= 0X08; //
推挽输出

      PC_CR2 |= 0X00; //10M



      PC_DDR &= ~0X04;  //
输入
RX---PC2

      PC_CR1 |= 0X04;   //
上拉输入

#endif

/*EXIT---PB4---PB5*/

PB_DDR &= ~0X10; //
输入

PB_CR1 |= 0X10; //
上拉输入

PB_CR2 |= 0X10; //
中断使能



PB_DDR &= ~0X20; //
输入

PB_CR1 |= 0X20; //
上拉输入

PB_CR2 |= 0X20; //
中断使能



/*PWM---TIM2_CH2*/

PB_DDR |= 0X04;

PB_CR1 |= 0X04;

PB_CR2 |= 0X04;

PB_ODR |= 0X04;



/*led

*/

PC_DDR |= 0X80; //
输出

  PC_ODR |= 0X80; //
拉高置
1

   PC_CR1 |= 0X80; //
推挽输出

   PC_CR2 |= 0X80; //10M

}


使用特权

评论回复
8
guanjiaer|  楼主 | 2021-6-4 20:13 | 只看该作者
GPIO的复用功能

  STM8L内部集成了控制端口复用的寄存器,不想STM8S那样需要在stvp工具中设置,这一点是很方便的,配置起来也很简单,只需要简单的几个寄存器就可以了。





  以串口为例,串口默认的接口为PC3和PC2,我们可以执行SYSCFG_RMPCR1 |= 0X20;就可以用PC5和PC6来进行串口通讯。

void GPIO_AF(void)

{

  SYSCFG_RMPCR1 |= 0X20;

}



使用特权

评论回复
9
guanjiaer|  楼主 | 2021-6-4 20:15 | 只看该作者
定时器

概述:

  STM8L15X
芯片有三种不同类型的定时器
:



高级控制型:Timer1
;通用型
:Timer2/3/5
;基础型
:Timer4


  

不同的定时器功能有所差异,无非也就是输入捕获,输出比较,更新溢出,PWM
等,配置定时器必须要做的就是
(时钟分频
---
重装载
---
计数方式
---
中断使能
---
开启计数)
有其他功能就再配置其他的寄存器,
PWM
要配置起模式,通道,有效电平以及占空比

相关的寄存器默认值就行很方便




bit7:
预装载使能

bit6:
对齐方式

bit4:

计数方向

bit0:

计数使能




时钟源分频系数,
3

bit
,分频值为(
1--128

2
的整数次幂)


  






重装载寄存器,发生溢出事件后自动重新装载


  

bit7:
  BREAK
中断

bit6:
触发中断

bit2:

捕获比较
2

bit1:
捕获比较
2

bit0:
更新中断

定时器
2有两路PWM(捕获比较通道)

寄存器有TIMx_CCMR1和TIMx_CCMR2在输入和输出模式下配置功能也不一样,以下介绍输出模式下的配置




bit4--bit6
   PWM
模式

bit3:
预装载


bit0--bit1:
通道输入输出


bit4--bit5:
配置通道
2


bit1:
有效电平

bit0:
输出使能

该寄存器集成了通道
1
和通道
2
的配置


使用特权

评论回复
10
guanjiaer|  楼主 | 2021-6-4 20:16 | 只看该作者
void InitTimer2( void )

{

TIM2_CR1  |= 0x10; //
向下计数

TIM2_PSCR = 0X07; //128
分频



TIM2_ARRH = 0X07; //
重装载值

      TIM2_ARRL = 0XD0;



TIM2_CCMR2 |= 0X70; //PWM2----
使能预装载
----
通道
1
输出

TIM2_CCER1 |= 0X10; //
高电平有效
-----
通道输出使能

TIM2_CCR2H = 0X03;

TIM2_CCR2L = 0XE8;

TIM2_BKR = 0x80; //
必须加,使能通道输出



TIM2_CCR = (TIM2_ARRH << 8 | TIM2_ARRL);

TIM2_IER  = 0x01;  /*  
允许更新中断
*/

TIM2_CR1  |= 0x01;  /*  
计数器使能,开始计数  
*/

}

需要注意的是在配置定时器2

PWM
功能时,
STM8L

STM8S
要多配置一个寄存器

TIM2_BKR = 0x80; //
必须加,使能通道输出

配置时也要讲相应的通道IO
进行配置,相关的时钟开关也要打开


使用特权

评论回复
11
guanjiaer|  楼主 | 2021-6-4 20:17 | 只看该作者
串口

串口配置有以下几处:

数据字长,奇偶检验,停止位个数,波特率配置

使用过程中要注意相应的状态为(发送完成,接收完成等)

状态寄存器USART_SR


数据寄存器USART_DR


波特率寄存器1 USART_BRR1


波特率寄存器2 USART_BRR2


控制寄存器1 USART_CR1;

控制寄存器2 USART_CR2;

控制寄存器3 USART_CR3;

控制寄存器4 USART_CR4;

控制寄存器5 USART_CR5;

保护时间寄存器 USART_GTR


分频寄存器 USART_PSCR



bit4:

字长


bit2:
校验使能


bit1:
奇偶校验


bit0:
校验中断







bit7:
发送空中断

bit6:
发送完成中断

bit5:
接收中断

bit3:
发送使能

bit2:
接收使能


bit4--bit5:

停止位










需要注意的是波特率寄存器对接收和发送是一样的,通过对
BRR1

BRR2
的编程实现。写
BRR2
应当先于写
BRR1
,因为写
BRR1
会更新波特率计数器。


使用特权

评论回复
12
guanjiaer|  楼主 | 2021-6-4 20:17 | 只看该作者
void UART_Init(void)

{

     USART1_CR1=0x00;          //
设置
M
字长,
8
位数据位

     USART1_CR2=0x2c;          //
使能发送、接收;

     USART1_CR3=0x00;         //1
位停止位



     USART1_BRR2=0x03;       //
设置波特率为
9600

     USART1_BRR1=0x68;

}


使用特权

评论回复
13
guanjiaer|  楼主 | 2021-6-4 20:19 | 只看该作者
外部中断

关于外部中断,STM8L

STM8S
的区别还是比较大的,
STM8L
可以对具体的某一位开启外部中断,也可以对一组
IO
开启中断,而
STM8S
只能对一组
IO
开启中断,这也是
STM8L
低功耗的表现,相应的
STM8L
也多了几个外部中断向量,这个可以在头文件中看到。

在配置外部中断时我们首先要
CPU_CCR = 0X28;I1 I0
全部写
1
时才可以配置其他的寄存器


  


下面的程序是配置
PB4的外部中断

  1

CPU_CCR

I1 I0
全部写
1


  2

EXTI_CR2
(配置
PB4


STM8L
提供了
EXTI_CR1

EXTI_CR2
两个寄存器来配置每组
IO
的某个位的中断边沿

EXTI_CR1
:配置每组
IO

bit0---bit3


  


EXTI_CR2
:配置每组
IO

bit4---bit6


  









使用特权

评论回复
14
guanjiaer|  楼主 | 2021-6-4 20:19 | 只看该作者
void InitEXTI( void )

{

  CPU_CCR = 0X28;

  EXTI_CR2 |= 0x02;//
下降沿触发

}



#pragma vector = EXTI4_vector

__interrupt void EXTI1_ISR( void )

{

  if(EXTI_SR1 == 0X10)//
外部中断
4
产生

  {

  EXTI_SR1 = 0x10;




  GPIOC_BIT7_FLASH;

  EXTI_FLASH = 1;

  }

}


使用特权

评论回复
15
guanjiaer|  楼主 | 2021-6-4 20:21 | 只看该作者
如果要配置
PB口的外部中断我们需要执行

1

EXTI_CR3 |= 0x02;//
下降沿触发

2

EXTI_CONF |= 0X02;

STM8L
提供了两个寄存器来配置每组
IO
的中断
EXTI_CR3

EXTI_CR4

EXTI_CR3
:配置端口
BDEF





EXTI_CR4
:配置端口
GH





另外要配置整组的中断,我们还需要进行中断向量的配置
EXTI_CONF


  








此寄存器的复位值为0x00
,默认我们的
IO
口的中断向量为
EXTI0----EXTI7(
所以上面程序中我们并没有对这个寄存器操作,因为默认就是
EXTI4)
,如果要使用
EXTIA----EXTIF(
某些
IO
没有
)
我们还需要配置此寄存器

相应的产生中断标志位的寄存器也是不一样,上面的是EXTI_SR1
,这里是
EXTI_SR2

EXTI_SR1





EXTI_SR2





使用特权

评论回复
16
guanjiaer|  楼主 | 2021-6-4 20:26 | 只看该作者
void InitEXTI( void )

  {

  CPU_CCR |= 0X28;



  EXTI_CR3 |= 0x02;//
下降沿触发

  EXTI_CONF |= 0X02;

  }



#pragma vector = EXTIB_vector

  __interrupt void EXTI1_ISR( void )

  {

  if(EXTI_SR2 == 0X01)//
外部中断
4
产生

  {

  EXTI_SR2 = 0x01;




  GPIOC_BIT7_FLASH;

  EXTI_FLASH = 1;

  }

  }



另外还要注意一点,在配置中断前关全局中断,配完相应的外设中断后,再开全局中断,这是一个标准操作,如果在外部中断配置前开全局中断,会导致
CPU_CCR
的值无法写入

配置的外部中断的IO
也要配置为输入模式,并打开
IO
口寄存器的外部中断,另外在产生中断后在中断处理函数中
EXTI_SR1 = 0x10;
要对中断标志位写
1
来清除中断标志

下面的程序配置了
PB4

PB5
,相对应的中断向量也不同
  EXTI4_vector

EXTI5_vector

  void InitEXTI( void )

  {

  CPU_CCR |= 0X28;



  EXTI_CR2 |= 0x0a;//
下降沿触发
bit4--bit5



  //EXTI_CR3 |= 0x02;//
下降沿触发

  //EXTI_CONF |= 0X02;

  }



#pragma vector = EXTI4_vector

  __interrupt void EXTI1_ISR( void )

  {

  if(EXTI_SR1 == 0X10)//
外部中断
4
产生

  {

  EXTI_SR1 = 0x10;

  GPIOC_BIT7_FLASH;

  EXTI_FLASH = 1;

  }

  }



#pragma vector = EXTI5_vector

  __interrupt void EXTI1_5ISR( void )

  {

  if(EXTI_SR1 == 0X20)//
外部中断
4
产生

  {

  EXTI_SR1 = 0x20;

  GPIOC_BIT7_FLASH;

  //EXTI_FLASH = 1;

  }

  }



使用特权

评论回复
17
guanjiaer|  楼主 | 2021-6-4 20:27 | 只看该作者
AD转换

ADC
配置寄存器
1 ADC_CR1

ADC
配置寄存器
2 ADC_CR2

ADC
配置寄存器
3 ADC_CR3

ADC
状态寄存器   
ADC_SR

ADC
数据高位寄存器
ADC_DRH

ADC
数据低位寄存器
ADC_DRL

ADC
高阈值高位寄存器
ADC_HTRH

ADC
高阈值低位寄存器
ADC_HTRL

ADC
低阈值高位寄存器
ADC_LTRH

ADC
低阈值低位寄存器
ADC_LTRL

ADC
通道序列寄存器
1 ADC_SQR1

ADC
通道选择扫描寄存器
2 ADC_SQR2

ADC
通道选择扫描寄存器
3 ADC_SQR3

ADC
通道选择扫描寄存器
4 ADC_SQR4

ADC
触发禁能
1-4 ADC_TRIGR1/2/3/4

具体的转换通道要看手册,开始转换后要等待几,
转换完成后,读取数据会清除相应的标志位,当不选择触发输入时,要
ADC1_SQR3 |= 0X40; //
选择扫描通道,不然无法转换


  



bit5--bit6:
精度配置

bit4:
模拟看门狗


bit2:

连续
/
单次

bit1:
开始

bit0:
开关





bit5--bit7:
采样时间

bit0--bit4:
转换通道


  



选择要扫描的通道


unsigned intReadSTM8AD(char idx )

{



ADC1_CR1 |= 0X01; //
使能
ADC

ADC1_CR3 |= idx; //
选择转换通道

ADC1_SQR3 |= 0X40; //
选择扫描通道





ADC1_CR1 |= 0x02; //
开始转换;

asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

while(!(ADC1_SR & 0X01));

return ADC1_DRH;

}


使用特权

评论回复
18
guanjiaer|  楼主 | 2021-6-4 20:28 | 只看该作者
EEPROM

eeprom
来说,
stm8L

stm8S
的寄存器配置都是一样的,只是
eeprom
的起始地址不一样,起始地址为
0x1000





顺序写入FLASH_DUKR=0xAE;FLASH_DUKR=0x56;
来进行解锁,






void InitEEPROM(void)

{

  /*
解锁
*/

  do

    {

  FLASH_DUKR=0xAE;

  FLASH_DUKR=0x56;

  }while((FLASH_IAPSR & 0x08)== 0x00);

}





unsigned char Stm8lEepromRead( unsigned char ucAddress )

{

  unsigned char ucReturn;

  unsigned char *p;

  p = (unsigned char *)(0x1000 + ucAddress * 0x04);//
读数据

  ucReturn = *p;



  return(ucReturn);

}





void Stm8lEepromWrite( unsigned char ucAddress, unsigned char ucData )

{

  unsigned char *p;

  p = (unsigned char *)(0x1000 + ucAddress * 0x04);//
转换地址

  *p = ucData; //
写数据

  while((FLASH_IAPSR & 0x04) == 0x00); //
等待写操作完成



}



使用特权

评论回复
19
guanjiaer|  楼主 | 2021-6-4 20:29 | 只看该作者
独立看门狗





IWDG_KR
用来配置开启看门狗,重装载,解锁控制命令





时钟源是低速内部时钟,在此寄存器中分频


  


重装载数值寄存器,在往
IWDG_KR
中写
0xAA
时重新装载喂狗



使用特权

评论回复
20
guanjiaer|  楼主 | 2021-6-4 20:29 | 只看该作者
void IWDG_SetPrescaler(void)

{

  IWDG_PR = 0x06;//
时钟源分频

}



void IWDG_SetReload(void)

{

  IWDG_RLR = 0xFF;//
看门狗重装载值

}



void IWDG_Refresh(void)

{

  IWDG_KR = (unsigned int)0xAA;//
重装载看门狗

}



void IWDG_Enable(void)

{

  IWDG_KR = (unsigned int)0XCC;//
开启看门狗

}



void IWDG_Access(void)

{

  IWDG_KR = (unsigned int)0X55;//
允许访问看门口狗寄存器

}



void IWDG_Configuration(void)

{

  IWDG_Enable();

  IWDG_Access();

  IWDG_SetPrescaler();

  IWDG_SetReload();

  IWDG_Refresh();

}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

4116

帖子

2

粉丝