前言
谁能想到光电专业的学生要学习那么多那么多的不同的课,最近(其实也有一段时间了)我们学习了嵌入式,虽然老师天天说这个简单,给一些一二年级的小学生学几天,他们也搞的很好,但是真正上手才知道,开始学习的阶段还是有些难度的。
一、目标任务
完成单片机STM8S103f上LED灯点亮,这里我准备采取2个方式来,(1)就是指定端口控制高低电平点亮LED,也是最基础的,(2)采用按键输入,LED灯输出的方式来点亮LED
二、任务步骤 1.查看引脚这个是第一步,也是最基础的一步,只要不那么粗心就没有问题,就是看一下电路图。
像这个就是LED灯的引脚,灯一的引脚就是PD2,灯二就PC7,以此类推。除了LED外,我们还需要KEY按键的引脚,在任务2和任务3中需要用到。
2.任务一包含头文件这个是必要的,学过C语言的都知道,像我们学习的这个板子,编写程序在顶端得加上这个命令。
#include
我们要宏定义各个灯的开光控制,例如
#define LED1_ON() PD_ODR_bit.ODR2 = 0 #define LED2_ON() PC_ODR_bit.ODR7 = 0 #define LED3_ON() PC_ODR_bit.ODR6 = 0 #define LED4_ON() PC_ODR_bit.ODR3 = 0 #define LED1_OFF() PD_ODR_bit.ODR2 = 1 #define LED2_OFF() PC_ODR_bit.ODR7 = 1 #define LED3_OFF() PC_ODR_bit.ODR6 = 1 #define LED4_OFF() PC_ODR_bit.ODR3 = 1
LED1_ON()就是给LED1所在引脚一个低电平,点亮LED1,PD和最后的2指这个命令的对象是PD2引脚,ODR表示输出模式下写入寄存器的数值通过锁存器加到相应的引脚上(也就是PD2),bit表示位数,ODR2表示这个引脚在ODR输出寄存器的第3位。 OFF宏定义与ON差不多,给目标引脚一个高电平,使得LED灯熄灭。
我们需要什么引脚,就需要将这些引脚进行一个初始化操作,编写对应的初始化函数。
void LED_Init()
{
PD_DDR_bit.DDR2 = 1;
PD_CR1_bit.C12 = 1;
PD_CR2_bit.C22 = 1;
PC_DDR_bit.DDR7 = 1;
PC_CR1_bit.C17 = 1;
PC_CR2_bit.C27 = 1;
PC_DDR_bit.DDR6 = 1;
PC_CR1_bit.C16 = 1;
PC_CR2_bit.C26 = 1;
PC_DDR_bit.DDR3 = 1;
PC_CR1_bit.C13 = 1;
PC_CR2_bit.C23 = 1;
}
viod LED_Init()就是定义一个叫LED_Init的函数,函数的第一句和宏定义OFF好像有几分相似,但是它们表达的意思很不同。
DDR是数据方向寄存器,PD_DDR_bit.DDR2 表示PD2这个引脚的数据方向寄存器,有2个方向可以选择,如果想这个成为输出端,就置1,成为输入端,就置0,很明显,我们这里是要把LED灯作为输出端口,所有要把四个LED灯的引脚的ODR寄存器置1。
CR2是端口控制寄存器1,PD_CR1_bit.C12表示PD2这个引脚的端口控制寄存器1,它在不同的DDR下有不同的选择模式,在DDR置1的情况下,CR1是输出模式选择器,CR1置0就是模拟开漏输出,置1就是推挽输出。
CR2是端口控制寄存器2,PD_CR1_bit.C12表示PD2这个引脚的端口控制寄存器2,和1一样有不同的选择模式,在DDR置一的情况下,CR2是输出速度选择器,CR2置0,输出速度最大为2MHZ,置1,输出速度最大为10MHZ。
所以3句在一起就,让LED灯引脚作为输出端,并且输出方式为最大10MHZ的推挽输出。
初始化函数写完,我们就可以开始编写主函数了。
int main(void)
{
CLK_CKDIVR = 0x00;
LED_Init();
while(1)
{
LED1_OFF();
delay(1000);
LED2_OFF();
delay(1000);
LED2_ON();
LED3_OFF();
delay(1000);
LED3_ON();
delay(1000);
LED4_OFF();
delay(1000);
LED2_OFF();
LED4_ON();
delay(1000);
}
}
CLK_CKDIVR是一个时钟初始化函数,这里不细讲,我们只需要知道它选择了整个系统为1分频。
主函数里申用LED_Init(),将LED灯都完成初始化。
在while死循环里申用LED的开关命令,有一个小小的提醒,LED灯一开始就是开着的。烧录程序之后,看到的现象为LED1灭-LED2灭-LED2亮-LED3灭-LED3亮-LED4灭-LED2灭/LED4亮
主函数里还有一个delay函数,就是一个延时函数,目的是防止LED灯亮灭时间间隔太快,看不清楚现象。
void delay(unsigned int ms)
{
unsigned int x,y;
for(x = ms;x>0;x--)
for(y = 1000;y>0;y--);
}
3.任务二
用按键输入来控制LED灯,只要在任务一的基础上进行一些删减即可
首先,将任务一中的宏定义删除,我们在任务二中已经有了按键的输入来改变状态,这里需要的就是编辑按键的初始化函数。
void KEY_Init()
{
PA_DDR_bit.DDR3 = 0;
PA_CR1_bit.C13 = 1;
PA_CR2_bit.C23 = 0;
PD_DDR_bit.DDR3 = 0;
PD_CR1_bit.C13 = 1;
PD_CR2_bit.C23 = 0;
PC_DDR_bit.DDR5 = 0;
PC_CR1_bit.C15 = 1;
PC_CR2_bit.C25 = 0;
}
这里的按键引脚的PDR寄存器置0,表示这个引脚的数据方向是输入。在DDR置0,也就是引脚输入的情况下,CR1置1表示上拉输出,置0表示浮空输出,观察按键的电路图,显然这里要选择上拉输出。输入模式下的CR2置0表示禁止外部中断,置1表示允许外部中断,这里用不到外部中断,置0即可。所以3句话的意思,就是将按键所对应的引脚设定为上拉输入的输入端,并且禁止外部中断(不设置KEY初始化函数其实也行,不过这样规范一些)。
在主函数里,我们要用按键状态的变化来作为输入数据,进而改变LED灯的状态。
int main(void)
{
CLK_CKDIVR = 0x00;
LED_Init();
KEY_Init();
while(1)
{
if(PA_IDR_bit.IDR3==0)
{
delay(100);
if(PA_IDR_bit.IDR3==1)
{
delay(100);
PD_ODR ^= 0x04;
PC_ODR ^= 0x40;
}
}
if(PD_IDR_bit.IDR3==0)
{
delay(100);
if(PD_IDR_bit.IDR3==1)
{
delay(100);
PC_ODR ^= 0x80;
PC_ODR ^= 0x08;
}
}
if(PC_IDR_bit.IDR5==0)
{
delay(100);
if(PD_IDR_bit.IDR5==1)
{
delay(100);
PD_ODR ^= 0x04;
PC_ODR ^= 0x40;
PC_ODR ^= 0x80;
PC_ODR ^= 0x08;
}
}
}
}
在while循环里,我所编辑的是一个if语句,if里的PA_IDR_bit.IDR3==0,IDR是输出寄存器的一种,不论引脚是输入还是输出模式,都可以通过该寄存器读入引脚状态值他,这个寄存器为只读寄存器。这句话的意思是,如果PA3(按键1)被按下,下一个则是,如果PA3被松开,中间加了一个delay函数来延时,在按键1被按下又弹起后,将对应LED灯引脚状态置反。
PD_ODR ^= 0x04,0x04是16进制,换算成二进制就是100,查看ODR寄存器表
100,1对应的就是ODR2,所以对应的引脚是PD2(LED灯1),将它的状态置反,在循环就是一直以固定的频率闪光。
总结
以上就是LED的一个基本的点亮,还有一些其他方式来点亮LED灯,像中断改变状态和调用库函数(库函数的工程配置不一样),再以后可能也会提到。



