学习CH04示例程序
注释:
//=====================================================================
//文件名称:main.s
//功能概要:汇编编程调用GPIO构件控制小灯闪烁(利用printf输出提示信息)
//版权所有:苏大嵌入式(sumcu.suda.edu.cn)
//版本更新:201808-202311
//=====================================================================
.include "include.inc" //头文件中主要定义了程序中需要使用到的一些常量
//(0)数据段与代码段的定义
//(0.1)定义数据存储data段开始,实际数据存储在RAM中
.section .data
//(0.1.1)定义需要输出的字符串,标号即为字符串首地址,\0为字符串结束标志
hello_information: //字符串标号
.ascii "--------------------------------------------------------------\n"
.ascii "金葫芦提示: \n"
.ascii "LIGHT:ON--第一次用纯汇编点亮的蓝色发光二极管,太棒了! \n"
.ascii " 这只是万里长征第一步,但是,万事开头难, \n"
.ascii " 有了第一步,坚持下去,定有收获! \n"
.ascii "--------------------------------------------------------------\n\0"
data_format:
.ascii "%d\n\0" //printf使用的数据格式控制符
light_show1:
.ascii "LIGHT_BLUE:ON--\n\0" //灯亮状态提示
light_show2:
.ascii "LIGHT_BLUE:OFF--\n\0" //灯暗状态提示
light_show3:
.ascii "闪烁次数mLightCount=\0" //闪烁次数提示
//(0.1.2)定义变量
.align 4 //.word格式四字节对齐
mMainLoopCount: //定义主循环次数变量
.word 0
mFlag: //定义灯的状态标志,1为亮,0为暗
.byte 'A'
.align 4
mLightCount:
.word 0
//(0.2)定义代码存储text段开始,实际代码存储在Flash中
.section .text
.syntax unified //指示下方指令为ARM和thumb通用格式
.thumb //Thumb指令集
.type main function //声明main为函数类型
.global main //将main定义成全局函数,便于芯片初始化之后调用
.align 2 //指令和数据采用2字节对齐,兼容Thumb指令集
//--------------------------------------------------------------------
//main.c使用的内部函数声明处
//--------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程,参见书稿)
main:
//(1)======启动部分(开头)主循环前的初始化工作======================
//(1.1)声明main函数使用的局部变量
//(1.2)【不变】关总中断
cpsid i
//(1.3)给主函数使用的局部变量赋初值
//(1.4)给全局变量赋初值
//(1.5)用户外设模块初始化
// 初始化蓝灯, r0、r1、r2是gpio_init的入口参数
ldr r0,=LIGHT_BLUE //r0指明端口和引脚(用=,因常量>=256,需用ldr)
movs r1,#GPIO_OUTPUT //r1指明引脚方向为输出
movs r2,#LIGHT_OFF //r2指明引脚的初始状态为亮
bl gpio_init //调用gpio初始化函数
// 初始化串口UART_User1
movs r0,#UART_User //串口号
ldr r1,=UART_BAUD //波特率
bl uart_init //调用uart初始化函数
//(1.6)使能模块中断
movs r0,#UART_User //串口号
bl uart_enable_re_int //调用uart中断使能函数
//(1.7)【不变】开总中断
cpsie i
//显示hello_information定义的字符串
ldr r0,=hello_information //待显示字符串首地址
bl printf //调用printf显示字符串
//bl . //在此打桩(.表示当前地址),理解发光二极管为何亮起来了?
//(1)======启动部分(结尾)=======================================
//(2)======主循环部分(开头)=====================================
main_loop: //主循环标签(开头)
//(2.1)主循环次数变量mMainLoopCount+1
ldr r2,=mMainLoopCount //r2←变量mMainLoopCount的地址
ldr r1, [r2] //r1←变量mMainLoopCount的内容
movs r3,#1 //r3←1
add r1,r3 //变量+1
str r1,[r2] //放回地址中
//(2.2)未达到主循环次数设定值,继续循环
ldr r2,=MainLoopNUM
cmp r1,r2
blO main_loop //未达到,继续循环
//(2.3)达到主循环次数设定值,执行下列语句,进行灯的亮暗处理
//(2.3.1)清除循环次数变量
ldr r2,=mMainLoopCount //r2←mMainLoopCount的地址
movs r1,#0
str r1,[r2]
//(2.3.2)如灯状态标志mFlag为'L',灯的闪烁次数+1并显示,改变灯状态及标志
//判断灯的状态标志
ldr r2,=mFlag
ldr r6,[r2]
cmp r6,#'L'
bne main_light_off //mFlag不等于'L'转
//mFlag等于'L'情况
ldr r3,=mLightCount //灯的闪烁次数mLightCount+1
ldr r1,[r3]
movs r4,#1
add r1,r4
str r1,[r3]
ldr r0,=light_show3 //显示“灯的闪烁次数mLightCount=”
bl printf
ldr r0,=data_format //显示灯的闪烁次数值
ldr r2,=mLightCount
ldr r1,[r2]
bl printf
ldr r2,=mFlag //灯的状态标志改为'A'
movs r7,#'A'
str r7,[r2]
ldr r0,=LIGHT_BLUE //亮灯
ldr r1,=LIGHT_ON
bl gpio_set
ldr r0, =light_show1 //显示灯亮提示
bl printf
//mFlag等于'L'情况处理完毕,转
b main_exit
//(2.3.3)如灯状态标志mFlag为'A',改变灯状态及标志
main_light_off:
ldr r2,=mFlag //灯的状态标志改为'L'
movs r7,#'L'
str r7,[r2]
ldr r0,=LIGHT_BLUE //暗灯
ldr r1,=LIGHT_OFF
bl gpio_set
ldr r0, =light_show2 //显示灯暗提示
bl printf
main_exit:
b main_loop //继续循环
//(2)======主循环部分(结尾)=====================================
.end //整个程序结束标志(结尾)
给出gpio_set(LIGHT_RED,LIGHT_OFF);语句中,LIGHT_RED和LIGHT_OFF的值是多少?
main.c:
user.h:
用直接地址编程方式,实现红绿蓝三灯轮流闪烁
//(1)======启动部分(结尾)==========================================
gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_ON);
//(2)======主循环部分(开头)=========================================
for(;;) //for(;;)(开头)
{
//(2.1)主循环次数+1,并判断是否小于特定常数
mMainLoopCount++; //+1
if (mMainLoopCount<=6556677) continue; //如果小于特定常数,继续循环
//(2.2)主循环次数超过特定常数,灯状态进行切换(这样灯会闪烁)
mMainLoopCount=0; //清主循环次数
//切换灯状态
if (mFlag=='B') //若灯状态标志为'B'
{
*gpio_bsrr|=(1<<7); //设置红灯“暗”
*gpio_brr|=(1<<9); //设置蓝灯“亮”
printf("蓝灯:亮\r\n"); //通过调试串口输出灯的状态
mFlag='G'; //改变状态标志
}
else if(mFlag=='G') //若灯状态标志为'G'
{
*gpio_bsrr|=(1<<9); //设置蓝灯“暗”
*gpio_brr|=(1<<8); //设置绿灯“亮”
printf("绿灯:亮\r\n"); //通过调试串口输出灯的状态
mFlag='R'; //改变状态标志
}
else if(mFlag=='R') //若灯状态标志为'R'
{
*gpio_bsrr|=(1<<8); //设置绿灯“暗”
*gpio_brr|=(1<<7); //设置红灯“亮”
printf("红灯:亮\r\n"); //通过调试串口输出灯的状态
mFlag='B'; //改变状态标志
}
} //for(;;)结尾
用调用构件方式,实现红绿蓝的八种组合轮流闪烁
//(1)======启动部分(结尾)==========================================
gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_ON);
//(2)======主循环部分(开头)========================================
for(;;) //for(;;)(开头)
{
//(2.1)主循环次数变量+1
mMainLoopCount++;
//(2.2)未达到主循环次数设定值,继续循环
if (mMainLoopCount<=12888999) continue;
//(2.3)达到主循环次数设定值,执行下列语句,进行灯的亮暗处理
//(2.3.1)清除循环次数变量
mMainLoopCount=0;
//(2.3.2)如灯状态标志mFlag为'L',灯的闪烁次数+1并显示,改变灯状态及标志
if (mFlag=='R') // 红色
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='G'; //灯的状态标志
gpio_set(LIGHT_RED,LIGHT_ON); //灯“亮”
printf(" LIGHT_RED:ON--\n\n"); //串口输出灯的状态
}
//(2.3.3)如灯状态标志mFlag为'G',改变灯状态及标志
else if (mFlag=='G') // 绿色
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='B'; //灯的状态标志
gpio_set(LIGHT_RED,LIGHT_OFF); //灯“暗”
gpio_set(LIGHT_GREEN,LIGHT_ON); //灯“亮”
printf(" LIGHT_GREEN:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='B') // 蓝色
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='Y'; //灯的状态标志
gpio_set(LIGHT_GREEN,LIGHT_OFF); //灯“暗”
gpio_set(LIGHT_BLUE,LIGHT_ON); //灯“亮”
printf(" LIGHT_BLUE:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='Y') // 黄色(红绿)
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='P'; //灯的状态标志
gpio_set(LIGHT_BLUE,LIGHT_OFF);
gpio_set(LIGHT_RED,LIGHT_ON);
gpio_set(LIGHT_GREEN,LIGHT_ON);
printf(" LIGHT_YELLOW:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='P') // 紫色(红蓝)
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='C'; //灯的状态标志
gpio_set(LIGHT_GREEN,LIGHT_OFF);
gpio_set(LIGHT_RED,LIGHT_ON);
gpio_set(LIGHT_BLUE,LIGHT_ON);
printf(" LIGHT_PURPLE:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='C') // 青色(蓝绿)
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='W'; //灯的状态标志
gpio_set(LIGHT_RED,LIGHT_OFF);
gpio_set(LIGHT_BLUE,LIGHT_ON);
gpio_set(LIGHT_GREEN,LIGHT_ON);
printf(" LIGHT_CYAN:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='W') // 白色(红绿蓝)
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='D'; //灯的状态标志
gpio_set(LIGHT_BLUE,LIGHT_ON);
gpio_set(LIGHT_GREEN,LIGHT_ON);
gpio_set(LIGHT_RED,LIGHT_ON);
printf(" LIGHT_WHITE:ON--\n\n"); //串口输出灯的状态
}
else if (mFlag=='D') // 暗色
{
mLightCount++;
printf("灯的闪烁次数 mLightCount = %d\n",mLightCount);
mFlag='R'; //灯的状态标志
gpio_set(LIGHT_GREEN,LIGHT_OFF);
gpio_set(LIGHT_BLUE,LIGHT_OFF);
gpio_set(LIGHT_RED,LIGHT_OFF);
printf(" DARK:ON--\n\n"); //串口输出灯的状态
}
} //for(;;)结尾