最近搞了搞STM8L系列的板子,感觉有些地方和S系列的不太一样,简单总结了相关外设的配置方法,相关的驱动都是可以运行的,详细内容如下
RCC时钟
概述:
系统时钟有四个时钟源,高速外部,高速内部,低速外部,低速内部,上电系统默认的时钟源为高速内部时钟,时钟频率为2M(16M/8).
HSI : 16M高速内部RC振荡器
HSE : 1-16M高速外部晶体振荡器
LSE : 32.768K低速外部晶体振荡器
LSI : 38K低速内部振荡器
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(时钟源的开启状态)
系统时钟分频系数,默认值为0x03(8分频),即默认值为2M(16M/8)
每个外设有相应的时钟开关,与stm32一样,在使用相应外设之前要打开时钟,寄存器为CLK_PCKENR1和CLK_PCKENR2
时钟源选择,我们可以使用默认值选择高速内部时钟
void InitSystemClock( void )
{
CLK_CKDIVR = 0x00;//系统时钟分频
/*打开全部的外设时钟*/
CLK_PCKENR1 |= 0xff;
CLK_PCKENR2 |= 0xff;
}
STM8L与STM8S的时钟部分没有太大的区别,需要注意的就是STM8L的外设时钟是关闭的(为了降低功耗),而STM8S的外设时钟是打开的,这个大家看一下相关寄存器的复位值就可以了,因此在使用stm8l的时候要记得打开相应的外设时钟
GPIO
IO的配置比较简单,STM8L和STM8S没有什么区别,总共也就那么几个寄存器
STM8L GPIO寄存器
一个数据方向寄存器 : Px_DDR
一个输出数据寄存器 : Px_ODR
一个输入寄存器 : Px_IDR
二个控制寄存器 : Px_CR1/Px_CR2
可选择的输入模式:浮动输入和带上拉输入
可选择的输出模式:推挽式输出
关于复用功能,IO口寄存器中没有特定的给出,我们在用到相关复用功能时,在相应外设中进行设置
端口输出寄存器
端口输入寄存器
端口方向寄存器
配置IO的时候要注意一下下面这两个寄存器,CR1主要选择输入输出的相应模式,CR2配置输出速度,要注意一下在适应外部中断的时候,相应的IO口的CR2要开启外部中断
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
}
GPIO的复用功能
STM8L内部集成了控制端口复用的寄存器,不想STM8S那样需要在stvp工具中设置,这一点是很方便的,配置起来也很简单,只需要简单的几个寄存器就可以了。
以串口为例,串口默认的接口为PC3和PC2,我们可以执行SYSCFG_RMPCR1 |= 0X20;就可以用PC5和PC6来进行串口通讯。
void GPIO_AF(void)
{
SYSCFG_RMPCR1 |= 0X20;
}
定时器
概述:
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的配置
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进行配置,相关的时钟开关也要打开
串口
串口配置有以下几处:
数据字长,奇偶检验,停止位个数,波特率配置
使用过程中要注意相应的状态为(发送完成,接收完成等)
状态寄存器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会更新波特率计数器。
void UART_Init(void)
{
USART1_CR1=0x00; //设置M字长,8位数据位
USART1_CR2=0x2c; //使能发送、接收;
USART1_CR3=0x00; //1位停止位
USART1_BRR2=0x03; //设置波特率为9600
USART1_BRR1=0x68;
}
外部中断
关于外部中断,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
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;
}
}
如果要配置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
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;
}
}
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;
}
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); //等待写操作完成
}
独立看门狗
IWDG_KR用来配置开启看门狗,重装载,解锁控制命令
时钟源是低速内部时钟,在此寄存器中分频
重装载数值寄存器,在往IWDG_KR中写0xAA时重新装载喂狗
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();
}
上一篇:单片机时钟的解析
下一篇:单片机编程使用C库函数
推荐阅读最新更新时间:2024-03-16 16:24