STM8的C语言编程.pdf
《STM8的C语言编程.pdf》由会员分享,可在线阅读,更多相关《STM8的C语言编程.pdf(34页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第 1 页 共 32 页献给迷茫中的STM8初学者本文内容整理与网络,适用于对单片机有一定的了解和熟悉的人.希望你们能够快速上手并应用 STM8.本文所有例程适用于 COSMIC 和 IAR 编译器,更多学习资料可以登录我们的 官网 和 论坛 查找。QIYONG第 2 页 共 32 页目 录STM8 的 C 语言编程(1)基本程序与启动代码分析.1STM8 的 C 语言编程(2)变量空间的分配.5STM8 的 C 语言编程(3)GPIO 输出.6STM8 的 C 语言编程(4)GPIO 输出和输入.8STM8 的 C 语言编程(5)8 位定时器应用之一.9STM8 的 C 语言编程(6)8 位
2、定时器应用之二.10STM8 的 C 语言编程(7)16 位定时器的中断应用.14STM8 的 C 语言编程(8)UART 应用.16STM8 的 C 语言编程(9)EEPROM 应用.20STM8 的 C 语言编程(10)修改 CPU 的时钟.22STM8 的 C 语言编程(11)切换时钟源.25STM8 的 C 语言编程(12)AD 转换.27STM8 的 C 语言编程(13)蜂鸣器.29STM8 的 C 语言编程(14)PWM.30第 1 页 共 32 页STM8STM8STM8STM8 的的 C C C C 语言编程(语言编程(1 1 1 1)基本程序与启动代码分析)基本程序与启动代码
3、分析现在几乎所有的单片机都能用 C 语言编程了,采用 C 语言编程确实能带来很多好处,至少可读性比汇编语言强多了。在 STM8 的开发环境中,可以通过新建一个工程,自动地建立起一个 C 语言的框架,生成后开发环境会自动生成 2 个 C 语言的程序,一个是 main.c,另一个是 stm8_interrupt_vector.c。main.c 中就是一个空的 main()函数,如下所示:/*MAIN.C file*Copyright(c)2002-2005 STMicroelectronics*/main()while(1);而在 stm8_interrupt_vector.c 中,就是声明了对应
4、该芯片的中断向量,如下所示:/*BASIC INTERRUPT VECTOR TABLE FOR STM8 devices*Copyright(c)2007 STMicroelectronics*/typedef void far(*interrupt_handler_t)(void);struct interrupt_vectorunsigned char interrupt_instruction;interrupt_handler_t interrupt_handler;far interrupt void NonHandledInterrupt(void)/*in order to d
5、etect unexpected events during development,it is recommended to set a breakpoint on the following instruction*/return;extern void _stext();/*startup routine*/struct interrupt_vector const _vectab=0 x82,(interrupt_handler_t)_stext,/*reset*/0 x82,NonHandledInterrupt,/*trap*/0 x82,NonHandledInterrupt,/
6、*irq0*/第 2 页 共 32 页0 x82,NonHandledInterrupt,/*irq1*/0 x82,NonHandledInterrupt,/*irq2*/0 x82,NonHandledInterrupt,/*irq3*/0 x82,NonHandledInterrupt,/*irq4*/0 x82,NonHandledInterrupt,/*irq5*/0 x82,NonHandledInterrupt,/*irq6*/0 x82,NonHandledInterrupt,/*irq7*/0 x82,NonHandledInterrupt,/*irq8*/0 x82,Non
7、HandledInterrupt,/*irq9*/0 x82,NonHandledInterrupt,/*irq10*/0 x82,NonHandledInterrupt,/*irq11*/0 x82,NonHandledInterrupt,/*irq12*/0 x82,NonHandledInterrupt,/*irq13*/0 x82,NonHandledInterrupt,/*irq14*/0 x82,NonHandledInterrupt,/*irq15*/0 x82,NonHandledInterrupt,/*irq16*/0 x82,NonHandledInterrupt,/*ir
8、q17*/0 x82,NonHandledInterrupt,/*irq18*/0 x82,NonHandledInterrupt,/*irq19*/0 x82,NonHandledInterrupt,/*irq20*/0 x82,NonHandledInterrupt,/*irq21*/0 x82,NonHandledInterrupt,/*irq22*/0 x82,NonHandledInterrupt,/*irq23*/0 x82,NonHandledInterrupt,/*irq24*/0 x82,NonHandledInterrupt,/*irq25*/0 x82,NonHandle
9、dInterrupt,/*irq26*/0 x82,NonHandledInterrupt,/*irq27*/0 x82,NonHandledInterrupt,/*irq28*/0 x82,NonHandledInterrupt,/*irq29*/;在 stm8_interrupt_vector.c 中,除了定义了中断向量表外,还定义了空的中断服务程序,用于那些不用的中断。当然在自动建立时,所有的中断服务都是空的,因此,除了第 1 个复位的向量外,其它都指向那个空的中断服务函数。生成框架后,就可以用 Build 菜单下的 Rebuild All 对项目进行编译和连接,生成所需的目标文件,然后
10、就可以加载到 STM8 的芯片中,这里由于 main()函数是一个空函数,因此没有任何实际的功能。不过我们可以把这个框架对应的汇编代码反出来,看看 C 语言生成的代码,这样可以更深入地了解 C 语言编程的特点。生成的代码包括 4 个部分,如图 1、图 2、图 3、图 4 所示。第 3 页 共 32 页图 1图 2第 4 页 共 32 页图 3图 4图 1 显示的是从内存地址 8000H 开始的中断向量表,中断向量表中的第 1 行 82008083H 为复位后单片机运行的第 1 跳指令的地址。从表中可以看出,单片机复位后,将从 8083H 开始运行。其它行的中断向量都指向同一个位置的中断服务程序
11、 80D0H。图 2 显示的是 3 个字节,前 2 个字节 8083H 为复位后的第 1 条指令的地址,第 3 个字节是一个常量0,后面的启动代码要用到。图 3 显示的是启动代码,启动代码中除了初始化堆栈指针外,就是初始化 RAM 单元。由于目前是一个空的框架,因此在初始化完堆栈指针(设置成 0FFFH)后,由于 8082H 单元的内容为 0,因此程序就跳到了 80B1H,此处是一个循环,将 RAM 单元从 0 到 5 初始化成 0。然后由于寄存器 X 设置成 0100H,就直接通过 CALL main 进入 C 的 main()函数。图 4 显示的是 main()函数和中断服务函数,main
12、()函数对应的代码就是一个无限的循环,而中断服务函数就一条指令,即中断返回指令。通过分析,可以看出用 C 语言编程时,比汇编语言编程时,就是多出了一段启动代码。第 5 页 共 32 页STM8STM8STM8STM8 的的 C C C C 语言编程(语言编程(2 2 2 2)变量空间的分配)变量空间的分配采用 C 这样的高级语言,其实可以不用关心变量在存储器空间中是如何具体分配的。但如果了解如何分配,对编程还是有好处的,尤其是在调试时。例如下面的程序定义了全局变量数组 buffer 和一个局部变量 i,在 RAM 中如何分配的呢?/*MAIN.C file*Copyright(c)2002-2
13、005 STMicroelectronics*/unsigned char buffer10;/定义全局变量main()unsigned char i;/定义局部变量for(i=0;i10;i+)bufferi=0 x55;我们可以通过 DEBUG 中的反汇编窗口,看到如下的对应代码:从这段代码中可以看到,全局变量 buffer 被分配到空间从地址 0000H 到 0009H。而局部变量 i 则在堆栈空间中分配,通过 PUSH A 指令,将堆栈指针减 1,腾出一个字节的空间,而 SP+1 指向的空间就是分配给局部变量使用的空间。由此可以得出初步的结论,对于全局变量,内存分配是从低地址 0000
14、H 开始向上分配的。而局部变量则是在堆栈空间中分配。另外从上一篇文章中,可以知道堆栈指针初始化时为 0FFFH。而根据 PUSH 指令的定义,当压栈后堆栈指针减 1。因此堆栈是从上往下使用的。因此根据内存分配和堆栈使用规则,我们在程序设计时,不能定义过多的变量,免得没有空间给堆栈使用。换句话说,当定义变量时,一定要考虑到堆栈空间,尤其是那些复杂的系统,程序调用层数多,这样就会占用大量的堆栈空间。总之,在单片机的程序设计时,由于 RAM 空间非常有限,要充分考虑到全局变量、局部变量、程序调用层数和中断服务调用对空间的占用。第 6 页 共 32 页STM8STM8STM8STM8 的的 C C C
15、 C 语言编程(语言编程(3 3 3 3)GPIOGPIOGPIOGPIO 输出输出与前些日子写的用汇编语言进行的实验一样,从今天开始,要在 ST 的三合一开发板上,用 C 语言编写程序,进行一系列的实验。首先当然从最简单的 LED 指示灯闪烁的实验开始。开发板上的 LED1 接在 STM8 的 PD3 上,因此要将 PD3 设置成输出模式,为了提高高电平时的输出电流,要将其设置成推挽输出方式。这主要通过设置对应的 DDR/CR1/CR2 寄存器实现。利用 ST 的开发工具,先生成一个 C 语言程序的框架,然后修改其中的 main.c,修改后的代码如下。编译通过后,下载到开发板,运行程序,可以
16、看到 LED1 在闪烁,且闪烁的频率为 5HZ。/*MAIN.C file*Copyright(c)2002-2005 STMicroelectronics*/#include STM8S207C_S.h/函数功能:延时函数/输入参数:ms-要延时的毫秒数,这里假设 CPU 的主频为 2MHZ/输出参数:无/返 回 值:无/备注:无void DelayMS(unsigned int ms)unsigned char i;while(ms!=0)for(i=0;i250;i+);for(i=0;i75;i+);ms-;/函数功能:主函数/初始化 GPIO 端口 PD3,驱动 PD3 为高电平和低
17、电平/输入参数:ms-要延时的毫秒数,这里假设 CPU 的主频为 2MHZ/输出参数:无/返 回 值:无/备注:无main()PD_DDR=0 x08;PD_CR1=0 x08;/将 PD3 设置成推挽输出第 7 页 共 32 页PD_CR2=0 x00;while(1)PD_ODR=PD_ODR|0 x08;/将 PD3 的输出设置成 1DelayMS(100);/延时 100MSPD_ODR=PD_ODR&0 xF7;/将 PD3 的输出设置成 0DelayMS(100);/延时 100MS需要注意的是,当生成完框架后,为了能方便使用 STM8 的寄存器名字,必须包括 STM8S207C_
18、S.h,最好将该文件拷贝到 C:Program FilesSTMicroelectronicsst_toolsetinclude 目录下,拷贝到工程目录下。或者将该路径填写到该工程的 Settings中的 C Compiler 选项 Preprocessor 的 Additional include 中,这样编译时才会找到该文件。第 8 页 共 32 页STM8STM8STM8STM8 的的 C C C C 语言编程(语言编程(4 4 4 4)GPIOGPIOGPIOGPIO 输出和输入输出和输入今天要进行的实验,是利用 GPIO 进行输入和输出。在 ST 的三合一开发板上,按键接在 GPIO
19、 的 PD7 上,LED 接在 GPIO 的 PD3 上,因此我们要将 GPIO 的 PD7 初始化成输入,PD3 初始化成输出。关于 GPIO 的引脚设置,主要是要初始化方向寄存器 DDR,控制寄存器 1(CR1)和控制寄存器 2(CR2),寄存器的每一位对应 GPIO 的每一个引脚。具体的设置功能定义如下:DDRCR1CR2引脚设置000悬浮输入001上拉输入010中断悬浮输入011中断上拉输入100开漏输出110推挽输出1X1输出(最快速度为 10MHZ)另外,输出引脚对应的寄存器为 ODR,输入引脚对应的寄存器为 IDR。下面的程序是检测按键的状态,当按键按下时,点亮 LED,当按键抬
20、起时,熄灭 LED。同样也是利用 ST 的开发工具,先生成一个 C 语言程序的框架,然后修改其中的 main.c,修改后的代码如下。编译通过后,下载到开发板,运行程序,按下按键,LED 就点亮,抬起按键,LED 就熄灭了。另外,要注意,将 STM8S207C_S.h 拷贝到当前项目的目录下。/程序描述:检测开发板上的按键,若按下,则点亮 LED,若抬起,则熄灭 LED/按键接在 MCU 的 GPIO 的 PD7 上,LED 接在 MCU 的 GPIO 的 PD3 上/#include STM8S207C_S.hmain()PD_DDR=0 x08;PD_CR1=0 x08;/将 PD3 设置成
21、推挽输出PD_CR2=0 x00;while(1)/进入无限循环if(PD_IDR&0 x80)=0 x80)/读入 PD7 的引脚信号PD_ODR=PD_ODR&0 xF7;/如果 PD7 为 1,则将 PD3 的输出设置成 0,熄灭 LEDelsePD_ODR=PD_ODR|0 x08;/否则,将 PD3 的输出设置成 1,点亮 LED第 9 页 共 32 页STM8STM8STM8STM8 的的 C C C C 语言编程(语言编程(5 5 5 5)8 8 8 8 位定时器应用之一位定时器应用之一在 STM8 单片机中,有多种定时器资源,既有 8 位的定时器,也有普通的 16 位定时器,还
22、有高级的定时器。今天的实验是用最简单的 8 位定时器 TIM4 来进行延时,然后驱动 LED 闪烁。为了简单起见,这里是通过程序查询定时器是否产生更新事件,来判断定时器的延时是否结束。同样还是利用 ST 的开发工具,生成一个 C 程序的框架,然后修改其中的 main.c,修改后的代码如下。编译通过后,下载到开发板,运行程序,可以看到 LED 在闪烁,或者用示波器可以在 LED 引脚上看到方波。在这里要特别提醒的是,从 ST 给的手册上看,这个定时器中的计数器是一个加 1 计数器,但本人在实验过程中感觉不太对,经过反复的实验,我认为应该是一个减 1 计数器(也许是我拿的手册不对,或许是理解上有误
23、)。例如,当给定时器中的自动装载寄存器装入 255 时,产生的方波频率最小,就象下面代码中计算的那样,产生的方波频率为 30HZ 左右。若初始化时给自动装载寄存器装入 1,则产生的方波频率最大,大约为 3.9K 左右。也就是说实际的分频数为 ARR 寄存器的值+1。/程序描述:通过初始化定时器 4,进行延时,驱动 LED 闪烁/LED 接在 MCU 的 GPIO 的 PD3 上#include STM8S207C_S.hmain()/首先初始化 GPIOPD_DDR=0 x08;PD_CR1=0 x08;/将 PD3 设置成推挽输出PD_CR2=0 x00;/然后初始化定时器 4TIM4_IE
24、R=0 x00;/禁止中断TIM4_EGR=0 x01;/允许产生更新事件TIM4_PSCR=0 x07;/计数器时钟=主时钟/128=2MHZ/128/相当于计数器周期为 64uSTIM4_ARR=255;/设定重装载时的寄存器值,255 是最大值TIM4_CNTR=255;/设定计数器的初值/定时周期=(ARR+1)*64=16320uSTIM4_CR1=0 x01;/b0=1,允许计数器工作,b1=0,允许更新/设置控制器,启动定时器while(1)/进入无限循环while(TIM4_SR1&0 x81)=0 x00);/等待更新标志TIM4_SR1=0 x00;/清除更新标志PD_OD
25、R=PD_ODR 0 x08;/LED 驱动信号取反 LED 闪烁频率=2MHZ/128/255/2=30.63第 10 页 共 32 页STM8STM8STM8STM8 的的 C C C C 语言编程(语言编程(6 6 6 6)8 8 8 8 位定时器应用之二位定时器应用之二今天进行的实验依然是用定时器 4,只不过改成了用中断方式来实现,由定时器 4 的中断服务程序来驱动 LED 的闪烁。实现中断方式的关键点有几个,第一个关键点就是要打开定时器 4 的中断允许位,在定时器 4 的 IER寄存器中有定义。第二个关键点,就是打开 CPU 的全局中断允许位,在汇编语言中,就是执行 RIM 指令,在
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STM8 语言 编程
限制150内