IAR FOR STM8例程要点
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
IAR+STM8——EXTI外部中断控制寄存器
2013-03-21 23:23:15| 分类:STM8|举报|字号订阅
这块三合一的开发板上有且只有一个按键,没办法,就拿这唯一的按键来用吧。
吸取前面UART3的教训,先看开发板的原理图吧。
这个按键被接到了
STM8S207SB的PD7上,已做了上拉处理。
为了简单明了,还是点LED1吧。
按一下LED1亮,再按一下LED1灭。
好了,写程序吧。
#i nclude <iostm8s207sb.h>
#define LED1_FLASH PD_ODR_ODR3 = !PD_ODR_ODR3 // 开发板上的LED1接在PD3上
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
PD_CR2 = 0x80; // 使能PD7外部中断
}
void EXTI_init(void)
{
EXTI_CR1 = 0x80; // PD口下降沿触发中断
}
#pragma vector=0x02 // 这里很关键!看下面说明。
__interrupt void EXTI_PD7_TLI(void)
{
LED1_FLASH;
}
void init_devices(void)
{
asm("sim"); // 关全局中断
GPIO_init();
EXTI_init();
asm("rim"); // 开全局中断
}
void main( void )
{
init_devices();
// 主循环里没有程序需要执行
while(1);
}
这里着重要说明的一点是PD7的外部中断程序。
看了一下芯片手册,PD口外部中断EXTI3的中断向量号是6,想当然,又是想当然,按IAR的规矩中断向量要加2,就这样写#pragma vector=0x08,结果就是按下按键,程序没响应了,一直在中断里不出来。
接下来只能另想办法,仔细翻了资料后发现,PD7和PD其他端口不一样,PD7后面拖了个小尾巴TLI,再看手册上的TLI描述,乖乖,TLI拥有芯片最高级别中断,享有独立专用的中断向量号0,这下就好办了,按IAR的规矩,向量号加2,程序改成#pragma vector=0x02,重新来一遍编译、下载、运行,按键终于听话了。
IAR+STM8——UART串口发送与中断接收
2013-03-21 23:22:34| 分类:STM8|举报|字号订阅
STM8的UART功能强大,除了常规的串口异步通讯外,还拥有LIN主模式、红外编解码器、智能卡模拟等功能。
新手还是从基本的串口通讯入手,那些高级功能等熟练以后再慢慢研究吧。
#i nclude <iostm8s207sb.h>
void CLK_init(void)
{
CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M
}
void UART3_init(void)
{
UART3_BRR2 = 0x01; // 设置波特率9600
UART3_BRR1 = 0x34; // 8M/9600 = 0x341
UART3_CR2 = 0x2C; // 允许接收中断,允许接收,允许发送
}
#pragma vector=UART3_R_RXNE_vector
__interrupt void UART3_RX_RXNE(void)
{
unsigned char c;
c = UART3_DR; // 接收到数据了
while(!UART3_SR_TXE);
c++; // 把接收到的数据加1
UART3_DR = c; // 再发回去,为什么这么做?在电脑上串口调试软件里发1就收到2,发A就收到B,看运行结果比较方便
}
void init_devices(void)
{
asm("sim"); // 关全局中断
CLK_init();
UART3_init(); // 开发板上的串口接的是UART3,刚开始想当然的认为UART1,浪费我半个小时
asm("rim"); // 开全局中断
}
void main( void )
{
init_devices();
// 主循环里没有程序需要执行
while(1);
}
IAR+STM8——TIM1定时溢出中断
2013-03-21 23:20:56| 分类:STM8|举报|字号订阅
STM8的TIM1是16位高级控制定时器,作为新手不要急着玩高级功能,先从简单的定时溢出中断开始。
那么这个简单的目标就定为LED1亮500ms,灭500ms,循环往复,如此而已。
#i nclude <iostm8s207sb.h>
#define LED1_FLASH PD_ODR_ODR3 = !PD_ODR_ODR3 // 开发板上的LED1接在PD3上
void CLK_init(void)
{
CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M
}
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
}
void TIM1_init(void)
{
TIM1_PSCRH = 0x1F; // 8M系统时钟经预分频f=fck/(PSCR+1)
TIM1_PSCRL = 0x3F; // PSCR=0x1F3F,f=8M/(0x1F3F+1)=1000Hz,每个计
数周期1ms
TIM1_ARRH = 0x01; // 自动重载寄存器ARR=0x01F4=500
TIM1_ARRL = 0xF4; // 每记数500次产生一次中断,即500ms
TIM1_IER = 0x01; // 允许更新中断
TIM1_CR1 = 0x01; // 计数器使能,开始计数
}
#pragma vector=TIM1_OVR_UIF_vector
__interrupt void TIM1_OVR_UIF(void)
{
LED1_FLASH;
TIM1_SR1 = 0; // 清除更新中断标记,这步不能漏掉,否则会连续进入中断程序}
void init_devices(void)
{
asm("sim"); // 关全局中断
CLK_init();
GPIO_init();
TIM1_init();
asm("rim"); // 开全局中断
}
void main( void )
{
init_devices();
// 主循环里没有程序需要执行
while(1);
}
好了,同样编译、下载、运行,看结果吧
IAR+STM8——系统时钟
2013-03-21 23:20:24| 分类:默认分类|举报|字号订阅
STM8上电运行时默认使用内部16M的RC振荡器经8分频后的2M时钟频率作为系统时钟。
程序开始运行后可以通过设置相关寄存器来修改主时钟源,可以选择外部晶振作为主时钟源和CPU时钟分频。
那么这里就选择比较简单的操作,修改内部RC时钟预分频器获得8M系统时钟。
增加内部RC时钟预分频后的代码如下:
#i nclude <iostm8s207sb.h>
#define LED1_FLASH PD_ODR_ODR3 = !PD_ODR_ODR3 // 开发板上的LED1接在PD3上
void delay(unsigned int count)
{
while(count--);
}
void CLK_init(void)
{
CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M
}
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
}
void init_devices(void)
{
CLK_init();
GPIO_init();
}
void main( void )
{
init_devices();
while(1)
{
delay(50000);
LED1_FLASH;
}
}
IAR+STM8——GPIO
2013-03-21 23:20:02| 分类:STM8|举报|字号订阅
第二天,从最基本的IO操作开始学习。
在STM上IO绝大多数是GPIO。
刚开始学习,测试程序不要搞复杂,越简单越不容易出错。
下面是代码,没有使用STM8官方固件库。
// GPIO测试
#i nclude <iostm8s207sb.h>
#define LED1_FLASH PD_ODR_ODR3 = !PD_ODR_ODR3 // 开发板上的LED1接在PD3上
void delay(unsigned int count)
{
while(count--);
}
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
}
void init_devices(void)
{
GPIO_init();
}
void main( void )
{
init_devices();
while(1)
{
delay(50000);
LED1_FLASH;
}
}
IAR+STM8——ADC模数转换器
2013-03-21 23:23:47| 分类:STM8|举报|字号订阅
今天有空来继续写学习笔记。
STM8片上集成了10位逐次比较型模数转换器,在开发板上有个电位器接到了AIN3,但没有可以显示数据的LED数码管或LCD液晶显示屏,怎么办呢?通过前面的学习,这个问题不难解决,在这里可以把AD采集数据通过UART发送到电脑上显示。
#i nclude <iostm8s207sb.h>
void CLK_init(void)
{
CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M }
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
PD_CR2 = 0x80; // 使能PD7外部中断
}
void EXTI_init(void)
{
EXTI_CR1 = 0x80; // PD口下降沿触发中断
}
#pragma vector=0x02
__interrupt void EXTI_PD7_TLI(void)
{
unsigned int value;
ADC_CSR &= ~0x80; // 清除EOC转换结束标志
ADC_CR1 |= 0x01; // 开始单次转换
while(!(ADC_CSR&0x80)); // 等待单次转换完成
value = ((int)ADC_DRH<<2); // 先读高8位,默认设置数据左对齐value |= ADC_DRL; // 再读低8位
while(!UART3_SR_TXE);
UART3_DR = value; // 通过UART3发送AD采样结果
while(!UART3_SR_TXE);
UART3_DR = value>>8;
}
void ADC_init(void)
{
ADC_CSR = 0x03; // ADC输入引脚AIN3
ADC_CR1 = 0x01; // ADC开启
}
void UART3_init(void)
{
UART3_BRR2 = 0x01;
UART3_BRR1 = 0x34; // 8M/9600 = 0x341
UART3_CR2 = 0x0C; // 允许接收,允许发送
}
void init_devices(void)
{
asm("sim");
CLK_init();
GPIO_init();
EXTI_init();
ADC_init();
UART3_init();
asm("rim");
}
void main( void )
{
init_devices();
// 主循环里没有程序需要执行
while(1);
}
在本例中仅使用了ADC的单次转换模式,每按一次按键进行一次AD转换,并把转换结果通过UART发送,这样可以在电脑上通过超级终端或串口调试软件查看数据。
通过这次测试,还发现一个现象,如果把清除EOC转换结束标志放在读取数据之后,那么在下次启动单次转换后,EOC标志位会自动置位,此时必须人为的等待7us后才能读到正确的数据,否则只能读到上一次的转换数据,可能这是STM8的ADC与其他MCU不同之处。
IAR+STM8——PWM
2013-03-21 23:24:19| 分类:STM8|举报|字号订阅
开发板上的LED1接在了PD3上,而PD3复用功能是TIM2_CC2,正好可以用来测试PWM功能。
当然板上的另外2个LED也可以用,LED2对应
PD2/TIM3_CC1,LED3对应PD0/TIM3_CC2。
本例程通过电位器来调整LED1的亮度。
#i nclude <iostm8s207sb.h>
void CLK_init(void)
{
CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M
}
void GPIO_init(void)
{
PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出
PD_CR1 = 0x08; // 设置PD3为推挽输出
}
void TIM2_init(void)
{
TIM2_CCMR2 = 0x70; // PWM 模式2
TIM2_CCER1 = 0x30; // CC2配置为输出
TIM2_ARRH = 0x03; // 配置PWM分辨率为10位,ARR=0x3FF
TIM2_ARRL = 0xFF; // PWM频率=8M/0x03FF=7820Hz
TIM2_CR1 = 0x01; // 计数器使能,开始计数
}
void ADC_init(void)
{
ADC_CSR = 0x03; // ADC输入引脚AIN3
ADC_CR1 = 0x01; // ADC开启
}
Run(void)
{
unsigned int value;
ADC_CSR &= ~0x80; // 清除EOC转换结束标志
ADC_CR1 |= 0x01; // 开始单次转换
while(!(ADC_CSR&0x80)); // 等待单次转换完成
value = ((int)ADC_DRH<<2); // 先读高8位,默认设置数据左对齐value |= ADC_DRL; // 再读低8位
TIM2_CCR2H = (unsigned char)(value>>8); // 更新CC2比较寄存器TIM2_CCR2L = (unsigned char)(value);
}
void init_devices(void)
{
asm("sim");
CLK_init();
GPIO_init();
TIM2_init();
ADC_init();
asm("rim");
}
void main( void )
{
init_devices();
while(1) Run();
}
STM8 互补PWM TIM1定时器输出成功
2014-10-22 15:11:50| 分类:STM8|举报|字号订阅
程序测试:
#include <iostm8s003f3.h>
void PWM_INIT()
{
CLK_PCKENR1 |= 0x80;//开启定时器1外设时钟
TIM1_EGR |= 0x01; //重新初始化TIM1
TIM1_CR1 = 0x00; //B7(0)可以直接写入B65(00)边缘对齐模式B4(0)向上计数B3(0)计数器不停止发生更新事件
TIM1_RCR = 0x00;
TIM1_PSCRH =0; //设定预分频为,16分频1M
TIM1_PSCRL =0x80; //PWM的时钟影响周期
TIM1_CCER1 = 0x0F; //CC2ER1开启1,2,高电平有效
TIM1_CCMR1 = 0x60; //PWM模式1,CC1配置入输出
TIM1_ARRH = 0; //设定重装载值
TIM1_ARRL = 0xFF; //PWM的周期
TIM1_CCR1H = 0;
TIM1_CCR1L = 0x80; // 占空比值
TIM1_CR1 |= 0x01; //使能TIM1计数器
TIM1_BKR |= 0x80;
}
void main()
{
PWM_INIT();
while(1);
}
非常重要注意,芯片的Option配置AFR7和AFR0修改如下图。