注册 登录
电子技术论坛 返回首页

戴上举的个人空间https://bbs.elecfans.com/?703024[收藏][复制][分享][RSS]

博客

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

热度33已有 10656 次阅读2013-1-29 11:32

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

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

  //-----------------------------------------

  //应广单片机软件基本框架例程

  //本例仅供参考,欢迎指正程序中的问题

  //本例是根据应广单片机的特点创建的基本程序框架

  //包含定时中断、外部中断、AD转换、段位数码管显示,简单按键处理等功能

  //用户在本例基础上很容易就能改出自己需要的程序

  //2012年12月15日

  //

  //作者:戴上举

  //邮箱:daishangju@163.com

  //博客:forum.eet-cn.com/BLOG_daishangju_334.HTM

  //电话:13509678051

  //Q Q:1514292225

  //-----------------------------------------

  .chip pdk22c12

  //{{PADAUK_CODE_OPtiON

  .Code_Option LVD 2.4V~2.9V // Maximum performance = 8 MIPS

  .Code_Option Security Enable // Security 7/8 words Enable

  //}}PADAUK_CODE_OPTION

  //#define MOB_FLASH_MODE

  KEY equ pa.5

  //定义数码管的IO口,这里是显示三个8

  LED_A equ pa.1

  LED_B equ pa.0

  LED_C equ pa.7

  LED_D equ pa.6

  LED_E equ pb.7

  LED_F equ pb.6

  LED_G equ pb.5

  LED_DP equ pb.1

  LED_COM1 equ pa.2

  LED_COM2 equ pa.3

  LED_COM3 equ pa.4

  LED_A_ON equ set1 LED_A

  LED_A_OFF equ set0 LED_A

  LED_B_ON equ set1 LED_B

  LED_B_OFF equ set0 LED_B

  LED_C_ON equ set1 LED_C

  LED_C_OFF equ set0 LED_C

  LED_D_ON equ set1 LED_D

  LED_D_OFF equ set0 LED_D

  LED_E_ON equ set1 LED_E

  LED_E_OFF equ set0 LED_E

  LED_F_ON equ set1 LED_F

  LED_F_OFF equ set0 LED_F

  LED_G_ON equ set1 LED_G

  LED_G_OFF equ set0 LED_G

  LED_DP_ON equ set1 LED_DP

  LED_DP_OFF equ set0 LED_DP

  SELECT_LED1 macro

  set1 LED_COM2

  set1 LED_COM3

  set0 LED_COM1

  endm

  SELECT_LED2 macro

  set1 LED_COM1

  set1 LED_COM3

  set0 LED_COM2

  endm

  SELECT_LED3 macro

  set1 LED_COM1

  set1 LED_COM2

  set0 LED_COM3

  endm

  ALL_LED_OFF macro

  set1 LED_COM1

  set1 LED_COM2

  set1 LED_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_DELAY macro

  delay 250

  delay 250

  endm

  word init_timer

  //用于数码管显示时进行查表转换

  word disp_ptr

  word disp_data

  word disp_data_temp

  byte Xms

  byte ms_cnt

  byte pb2_voltage

  //用于数码管显示

  byte disp1_buf

  byte disp2_buf

  byte disp3_buf

  byte disp_temp

  byte led1_buf

  byte led2_buf

  byte led3_buf

  //用于定时中断计时

  byte timer_cnt

  //用于单键按键判断

  byte key_cnt

  bit key_press_flag

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

  bit led_en_flag

  bit led_flash_flag

  bit update_disp_flag

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

  .romadr 0x000

  goto main0

  goto main1

  //应广单片机中断程序入口地址,所有中断共用同一个入口,需要用户自己判断中断类型

  .romadr 0x010

  pushaf

  if(intrq.T16) //定时中断

  {

  stt16 init_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)

  {

  delay 195

  ms_cnt--

  }

  Xms--

  }

  ret

  //----------------------------------------

  //

  //对PB2进行AD转换,得到上面的电压

  //----------------------------------------

  get_pb2_voltage:

  //对新的一路AD通道进行AD转换时,第一次转换的结果可能不可靠,这里连续转换两次,取第二次结果

  //如果连续对同一通道进行AD转换,可以只转换一次

  adcc = 0b10_0010_00 //enable ADC, select pb2

  ad_start = 1

  wait1 ad_start //等待AD转换结束

  a = adcr //放弃第一次转换结果

  ad_start = 1

  wait1 ad_start

  pb2_voltage = adcr //存储第二次转换结果

  ret

  //数码管BCD显示用的转换表,最后的两个0x00可以不要

  //数码管的a,b,...,g,dp分别对应bit7,bit6,...,bit0

  bcd_tbl: //0~9

  dc 0xFC,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

  ldtabl disp_ptr

  mov disp1_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

  ldtabl disp_ptr

  mov disp2_buf,a

  //得到数据管第三位LED3的BCD码

  disp_temp = disp_data_temp

  disp_ptr = bcd_tbl

  disp_ptr = disp_ptr + disp_temp

  ldtabl disp_ptr

  mov disp3_buf,a

  update_disp_flag = 1

  }

  ret

  //第一个内核程序入口

  //----------------FPPA0-------------------

  main0:

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

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

  //禁止中断和定时器

  disgint

  inten = 0

  mov a,0b000_11_111 //disable timer

  mov t16m,a

  //小延时后在修改其它系统状态设置

  delay 200

  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

  mov a,0b100_11_111

  mov t16m,a

  stt16 init_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

  call delayXms

  //得到按键初始状态,这样在按键损坏时不会误判按键按下或松开

  if(!KEY)

  {

  key_press_flag = 1

  }

  else

  {

  key_press_flag = 0

  }

  stt16 init_timer

  intrq = 0

  inten.T16 = 1 //打开定时中断

  inten.PB0 = 1 //打开PB0外部中断

  engint //允许中断

  set1 fppen.1 //打开第二个内核

  main0_loop:

  wdreset //clear watch dog

  //得到PB2的AD转换结果

  call get_pb2_voltage

  //AD转换完立即更新数码管显示缓冲区

  call update_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

  call delayXms

  goto main0_loop

  //第二个内核程序入口

  //----------------FPPA1-------------------

  main1:

  sp = 0x38 //设置第二个内核的堆栈地址

  delay 200

  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

  }

  goto main1_loop

  已编译,未调试

返回顶部