0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

应广单片机系列——基本应用程序框架

聚丰开发 2018-10-18 12:49 次阅读

注:本文是作者以前发表在其个人博客,现在发布到电子发烧友专栏


单片机工程师面对一种新单片机时,最希望的是能有一个简单的样例,这个样例连上仿真器就能运行,里面最好包含一些基本功能,这样工程师就可以在这个样例的基础上很快改出自己需要的代码。

这里我以应广pdk22c12写了一段程序框架,已经包含对这个单片机的各种基本设置,拿回去就可以自己进行仿真调试,相信能让新接触应广单片机的朋友很快上手。

//-----------------------------------------
//应广单片机软件基本框架例程
//本例仅供参考,欢迎指正程序中的问题
//本例是根据应广单片机的特点创建的基本程序框架
//包含定时中断、外部中断、AD转换、段位数码管显示,简单按键处理等功能
//用户在本例基础上很容易就能改出自己需要的程序

.chippdk22c12
//{{PADAUK_CODE_OPTION
.Code_OptionLVD2.4V~2.9V// Maximum performance = 8 MIPS
.Code_OptionSecurityEnable// Security 7/8 words Enable
//}}PADAUK_CODE_OPTION
//#define MOB_FLASH_MODE

KEYequpa.5

//定义数码管的IO口,这里是显示三个8
LED_Aequpa.1
LED_Bequpa.0
LED_Cequpa.7
LED_Dequpa.6
LED_Eequpb.7
LED_Fequpb.6
LED_Gequpb.5
LED_DPequpb.1
LED_COM1equpa.2
LED_COM2equpa.3
LED_COM3equpa.4
LED_A_ONequset1LED_A
LED_A_OFFequset0LED_A
LED_B_ONequset1LED_B
LED_B_OFFequset0LED_B
LED_C_ONequset1LED_C
LED_C_OFFequset0LED_C
LED_D_ONequset1LED_D
LED_D_OFFequset0LED_D
LED_E_ONequset1LED_E
LED_E_OFFequset0LED_E
LED_F_ONequset1LED_F
LED_F_OFFequset0LED_F
LED_G_ONequset1LED_G
LED_G_OFFequset0LED_G
LED_DP_ONequset1LED_DP
LED_DP_OFFequset0LED_DP
SELECT_LED1macro
set1LED_COM2
set1LED_COM3
set0LED_COM1
endm
SELECT_LED2macro
set1LED_COM1
set1LED_COM3
set0LED_COM2
endm
SELECT_LED3macro
set1LED_COM1
set1LED_COM2
set0LED_COM3
endm
ALL_LED_OFFmacro
set1LED_COM1
set1LED_COM2
set1LED_COM3
LED_A_OFF
LED_B_OFF
LED_C_OFF
LED_D_OFF
LED_E_OFF
LED_F_OFF
LED_G_OFF
LED_DP_OFF
endm

LED_DELAYmacro
delay250
delay250
endm

wordinit_timer
//用于数码管显示时进行查表转换
worddisp_ptr
worddisp_data
worddisp_data_temp

byteXms
bytems_cnt
bytepb2_voltage

//用于数码管显示
bytedisp1_buf
bytedisp2_buf
bytedisp3_buf
bytedisp_temp
byteled1_buf
byteled2_buf
byteled3_buf

//用于定时中断计时
bytetimer_cnt
//用于单键按键判断
bytekey_cnt
bitkey_press_flag

//定义标志位,用于数码管显示和闪烁控制
bitled_en_flag
bitled_flash_flag
bitupdate_disp_flag

//应广单片机程序入口,第一条必须为跳转到第一个内核主程序入口地址的指令,第二条为第二个内核,有几个内核就有几条
.romadr 0x000
gotomain0
gotomain1


//应广单片机中断程序入口地址,所有中断共用同一个入口,需要用户自己判断中断类型
.romadr 0x010
pushaf
if(intrq.T16)//定时中断
{
stt16init_timer//重设定时器
if(timer_cnt < 9) //得到1000ms间隔
{
timer_cnt ++
}
else
{
timer_cnt = 0
if(led_flash_flag)//数码管闪烁处理
{
led_flash_flag = 0
}
else
{
led_flash_flag = 1
}
}
intrq.T16 = 0
}
elseif(intrq.PB0)//PB0外部中断
{
if(pb.0)
{
//读到PB0状态为高,为上升沿
nop//添加用户自己的代码
}
else
{
//读到PB0状态为低,为下降沿
nop//添加用户自己的代码
}
}
intrq.AD = 0//强制清除AD中断标志位,防止意外进入AD中断后程序不停响应
intrq.PA0 = 0//强制清除PA0外部中断标志位,防止意外进入PA0中断后程序不停响应
popaf
reti

//----------------------------------------
//input: ms
//用该函数可以再4M的频率下得到近似1毫秒的延时,在第一个内核中调用中断会导致延时加长
//----------------------------------------
delayXms:
while(Xms)
{
wdreset//这里需要有清看门狗操作,否则有可能在长延时下导致看门狗溢出复位
ms_cnt = 20
while(ms_cnt)
{
delay195
ms_cnt--
}
Xms--
}
ret


//----------------------------------------
//
//对PB2进行AD转换,得到上面的电压
//----------------------------------------
get_pb2_voltage:
//对新的一路AD通道进行AD转换时,第一次转换的结果可能不可靠,这里连续转换两次,取第二次结果
//如果连续对同一通道进行AD转换,可以只转换一次
adcc = 0b10_0010_00//enable ADC, select pb2
ad_start = 1
wait1ad_start//等待AD转换结束
a = adcr//放弃第一次转换结果
ad_start = 1
wait1ad_start
pb2_voltage = adcr//存储第二次转换结果
ret

//数码管BCD显示用的转换表,最后的两个0x00可以不要
//数码管的a,b,...,g,dp分别对应bit7,bit6,...,bit0
bcd_tbl://0~9
dc0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0x00,0x00
//----------------------------------------
//以十进制形式显示数据disp_data
//只修改显示缓冲区
//----------------------------------------
update_led_disp_buf:
//a,b,...,g,dp --> bit7,bit6,...,bit0
if(!update_disp_flag)
{
disp_data_temp = disp_data//先将需要显示的数据放到临时中间变量中,防止转换时数据更新导致显示出错

//得到数据管第一位LED1的BCD码
disp_temp = 0
while(disp_data_temp >= 100)//直接用循环减实现除法
{
disp_data_temp = disp_data_temp - 100
disp_temp ++
}
disp_ptr = bcd_tbl//查表操作
disp_ptr = disp_ptr + disp_temp
ldtabldisp_ptr
movdisp1_buf,a
//得到数据管第二位LED2的BCD码
disp_temp = 0
while(disp_data_temp >= 10)
{
disp_data_temp = disp_data_temp - 10
disp_temp ++
}
disp_ptr = bcd_tbl
disp_ptr = disp_ptr + disp_temp
ldtabldisp_ptr
movdisp2_buf,a
//得到数据管第三位LED3的BCD码
disp_temp = disp_data_temp
disp_ptr = bcd_tbl
disp_ptr = disp_ptr + disp_temp
ldtabldisp_ptr
movdisp3_buf,a

update_disp_flag = 1
}

ret

//第一个内核程序入口
//----------------FPPA0-------------------
main0:

.ADJUST_OTP_IHRCR8MIPS// IHRC/2 = 8MIPS, WatchDog Disable, RAM 0,1 temporary be used

sp = 0x30//设置第一个内核的堆栈地址

//禁止中断和定时器
disgint
inten = 0
mova,0b000_11_111//disable timer
movt16m,a

//小延时后在修改其它系统状态设置
delay200
clkmd.1 = 1//打开看门狗,这个设置尽量靠前,以增强可靠性
wdreset//清看门狗

//设置IO口
pac = 0b1101_1111//PA5设置 IN
paph = 0b0000_0000
pbc = 0b1111_1010//PB2设为模拟输入不开上拉电阻,PB0设为输入
pbph = 0b0000_0000//poll high

ALL_LED_OFF

init_timer = 7768//从7768进行校准为100ms
mova,0b100_11_111
movt16m,a
stt16init_timer

//上电后清需要使用的变量
key_cnt = 0
disp1_buf = 0
disp2_buf = 0
disp3_buf = 0
led1_buf = 0
led2_buf = 0
led3_buf = 0
update_disp_flag = 0
timer_cnt = 0
disp_data = 000
led_en_flag = 1 //数码管进行显示

//将PB2设为模拟输入口进行AD转换
adcdi = 0b0000_0100//pb2 is analog input
adcc = 0b10_0010_00//enable ADC, select pb2
adcm = 0b000_0100_0//system clock/16
//adcm = 0b000_0111_0//system clock/128

//延时一段时间等系统稳定
Xms = 100
calldelayXms

//得到按键初始状态,这样在按键损坏时不会误判按键按下或松开
if(!KEY)
{
key_press_flag = 1
}
else
{
key_press_flag = 0
}


stt16init_timer
intrq = 0
inten.T16 = 1//打开定时中断
inten.PB0 = 1//打开PB0外部中断
engint//允许中断
set1fppen.1//打开第二个内核

main0_loop:

wdreset//clear watch dog

//得到PB2的AD转换结果
callget_pb2_voltage
//AD转换完立即更新数码管显示缓冲区
callupdate_led_disp_buf

if(!KEY)//电压恢复正常只要按键就立刻结束倒计时
{
if(key_cnt < 3)
{
key_cnt ++
}
else
{
if(!key_press_flag)
{
key_press_flag = 1//这里是按键按下
//按键切换数码管是否进行显示
if(led_en_flag)
{
led_en_flag = 0//数码管不显示
}
else
{
led_en_flag = 1//数码管显示
}
}
}
}
else
{
if(key_cnt)
{
key_cnt --
}
else
{
if(key_press_flag)
{
key_press_flag = 0//这里是按键松开
}
}
}

//延时50毫秒,目的是让第一个内核循环的时间大于第二个内核循环时间的两倍
//以保证显示缓冲区再次更新前第二个核已经做出响应,保证显示正确
Xms = 50
calldelayXms

gotomain0_loop

//第二个内核程序入口
//----------------FPPA1-------------------
main1:
sp = 0x38//设置第二个内核的堆栈地址
delay200
main1_loop:
if(update_disp_flag)//有数据更新时才进行更新
{
led1_buf = disp1_buf
led2_buf = disp2_buf
led3_buf = disp3_buf
update_disp_flag = 0
}

//第二个内核循环扫描显示数码管,这样可以得到没有闪烁的显示效果
if(led_en_flag)//数码管需要显示
{
//下面程序尽量让数码管每个段位的处理时间相同,这样可以保证各个段位亮度一致
//LED1
ALL_LED_OFF
LED_DELAY
SELECT_LED1
if(led1_buf.7)
{
LED_A_ON
}
LED_DELAY
LED_A_OFF
if(led1_buf.6)
{
LED_B_ON
}
LED_DELAY
LED_B_OFF
if(led1_buf.5)
{
LED_C_ON
}
LED_DELAY
LED_C_OFF
if(led1_buf.4)
{
LED_D_ON
}
LED_DELAY
LED_D_OFF
if(led1_buf.3)
{
LED_E_ON
}
LED_DELAY
LED_E_OFF
if(led1_buf.2)
{
LED_F_ON
}
LED_DELAY
LED_F_OFF
if(led1_buf.1)
{
LED_G_ON
}
LED_DELAY
LED_G_OFF
if(led1_buf.0)
{
LED_DP_ON
}
LED_DELAY
LED_DP_OFF
//LED2
ALL_LED_OFF
LED_DELAY
SELECT_LED2
if(led2_buf.7)
{
LED_A_ON
}
LED_DELAY
LED_A_OFF
if(led2_buf.6)
{
LED_B_ON
}
LED_DELAY
LED_B_OFF
if(led2_buf.5)
{
LED_C_ON
}
LED_DELAY
LED_C_OFF
if(led2_buf.4)
{
LED_D_ON
}
LED_DELAY
LED_D_OFF
if(led2_buf.3)
{
LED_E_ON
}
LED_DELAY
LED_E_OFF
if(led2_buf.2)
{
LED_F_ON
}
LED_DELAY
LED_F_OFF
if(led2_buf.1)
{
LED_G_ON
}
LED_DELAY
LED_G_OFF
if(led2_buf.0)
{
LED_DP_ON
}
LED_DELAY
LED_DP_OFF
//LED3
ALL_LED_OFF
LED_DELAY
SELECT_LED3
if(led3_buf.7)
{
LED_A_ON
}
LED_DELAY
LED_A_OFF
if(led3_buf.6)
{
LED_B_ON
}
LED_DELAY
LED_B_OFF
if(led3_buf.5)
{
LED_C_ON
}
LED_DELAY
LED_C_OFF
if(led3_buf.4)
{
LED_D_ON
}
LED_DELAY
LED_D_OFF
if(led3_buf.3)
{
LED_E_ON
}
LED_DELAY
LED_E_OFF
if(led3_buf.2)
{
LED_F_ON
}
LED_DELAY
LED_F_OFF
if(led3_buf.1)
{
LED_G_ON
}
LED_DELAY
LED_G_OFF
if(led3_buf.0)
{
LED_DP_ON
}
LED_DELAY
LED_DP_OFF
}
else//数码管不需要显示
{
ALL_LED_OFF
}

gotomain1_loop

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6044

    文章

    44632

    浏览量

    639404
收藏 人收藏

    评论

    相关推荐

    AN4875-AVR DD系列单片机入门

    电子发烧友网站提供《AN4875-AVR DD系列单片机入门.pdf》资料免费下载
    发表于 01-21 14:37 0次下载
    AN4875-AVR DD<b class='flag-5'>系列</b><b class='flag-5'>单片机</b>入门

    单片机Debug工具性能对比 单片机调试常用命令

    单片机(Microcontroller Unit, MCU)调试是嵌入式开发中的一个重要环节,它帮助开发者发现和修复代码中的错误,优化程序性能。不同的单片机和开发环境可能使用不同的调试工具和命令
    的头像 发表于 12-19 09:56 558次阅读

    单片机编程语言有哪些选择

    单片机(Microcontroller Unit,MCU)编程是指为单片机编写程序的过程,这些程序控制单片机的行为和功能。单片机广泛应用于嵌
    的头像 发表于 11-01 14:13 1074次阅读

    基于51单片机的手动数字时钟

    众多嵌入式控制应用系统提供灵活、高效的解决方案。本设计所使用的芯片可兼容以下所有的51系列单片机(包括AT系列和STC系列)。资料内容仿真实现(protues8.7) 本设计
    的头像 发表于 10-22 14:12 308次阅读
    基于51<b class='flag-5'>单片机</b>的手动数字时钟

    基于51单片机的遥控开关仿真(双机通信)

    灵活、高效的解决方案。本设计所使用的芯片可兼容以下所有的51系列单片机(包括AT系列和STC系列)。资料内容仿真实现(protues8.7)本设计利用protues8.7软件实现仿真设
    的头像 发表于 10-22 14:12 405次阅读
    基于51<b class='flag-5'>单片机</b>的遥控开关仿真(双机通信)

    单片机怎么写入程序

    程序通常涉及以下几个步骤: 选择单片机和开发环境 : 确定项目需求,选择合适的单片机型号。 安装相应的开发环境,如Keil、IAR、MPLAB等。 硬件连接 : 将单片机连接到开发板或
    的头像 发表于 10-21 11:21 1018次阅读

    单片机的中断机制

    单片机的中断机制是一种重要的处理方式,它允许单片机在执行主程序的过程中,能够暂停当前任务,转而处理外部或内部紧急事件。这种机制极大地提高了系统的响应速度和处理能力,使得单片机在各种应用
    的头像 发表于 10-17 18:03 1060次阅读

    通过DaVinci TMS320DM644x的串行接口加载基本应用程序

    电子发烧友网站提供《通过DaVinci TMS320DM644x的串行接口加载基本应用程序.pdf》资料免费下载
    发表于 10-16 11:52 0次下载
    通过DaVinci TMS320DM644x的串行接口加载基<b class='flag-5'>本应用程序</b>

    MCU前沿市场趋势:8位单片机和32位单片机

    的处理能力,所需的接口程度以及对于电池供电的设计的所有重要功耗曲线,仔细确定对MCU的要求。毫无疑问,32位单片机比8位设备具有更高的性能,但是工程师面临传统的选择,即在市场上最好的设备与应用程序的实际
    发表于 09-24 17:47

    keil可以读出单片机程序

    Keil是一款广泛应用于单片机程序开发的软件,它提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案。然而,关于Keil是否能直接“读出”单片机程序
    的头像 发表于 09-02 10:32 1306次阅读

    单片机烧录程序用什么软件

    单片机烧录程序单片机开发过程中的一个重要环节,涉及到将编写好的程序代码通过烧录器写入单片机的ROM中,以实现对
    的头像 发表于 09-02 10:05 1754次阅读

    单片机烧录程序可以重新烧吗

    单片机(Microcontroller Unit, MCU)是一种集成电路芯片,它将计算机的CPU、存储器、输入/输出接口等集成在一块芯片上,用于控制各种电子设备。单片机烧录程序是指将编写
    的头像 发表于 09-02 10:04 1630次阅读

    单片机烧录程序的线比单片机上的少还能烧录吗

    单片机烧录原理 单片机烧录是指将编写好的程序代码通过一定的方式传输到单片机的存储器中,使其能够按照程序的指令运行。这个过程通常需要使用烧录器
    的头像 发表于 09-02 09:54 639次阅读

    单片机烧录程序的基本步骤是什么

    单片机烧录程序的基础,它包含了单片机芯片、电源、接口等基本元件。在选择单片机开发板时,需要考虑以下几个方面: (1)单片机型号:根据项目需
    的头像 发表于 09-02 09:47 1553次阅读

    stm32单片机烧录程序会擦除原来的程序

    在STM32单片机烧录程序的过程中, 通常情况下会擦除原来的程序 ,并将新程序写入单片机的闪存(Flash)中。这一过程是通过烧录工具(如S
    的头像 发表于 09-02 09:42 2612次阅读