tag 标签: 应广

相关博文
  • 热度 23
    2012-12-22 15:50
    3357 次阅读|
    8 个评论
    经过一段时间的慎重考虑,在诸多朋友的支持下,决定在接下来的日子里,会尽可能多的写一些关于应广多核单片机应用的文章,希望能给有兴趣学习了解应广单片机的朋友提供到点滴帮助。 这个针对应广双核、多核单片机应用的系列,会以具体程序为例,在程序中加以注释,只要条件允许,例程都会经过调试,如果只是编译没有调试的,我会注明。 附件中的例程代码,读者可以自由使用,不需要通知我,如有可能,希望在代码中保留我的签名信息,深表感谢!  例程为利用应广单片机的特点,用软件实现理论速率可以达到1M的I2C通讯接口,如果是其它普通单片机,也可以用软件模拟出高速I2C,不同点是应广实现模拟后还能够实现各种控制功能,而其它普通单片则不能。 //----------------------------------------- //应广单片机软件实现高速I2C接口例程(SALVE模式) //本例仅供参考,欢迎指正程序中的问题 //本例利用应广单片机的双核特点 //用一个核专门对I2C接口的IO进行扫描等待 //对I2C接口的高低变化利用应广特有的IO状态等待指令高速实现IO口跳变判断 //利用定时器进行超时判断 //理论上可以让模拟的I2C接口达到1M的速率 //2012年12月15日 // //作者:戴上举 //邮箱:daishangju@163.com //博客:forum.eet-cn.com/BLOG_daishangju_334.HTM //电话:13509678051 //Q  Q:1514292225 //----------------------------------------- .chip p201cs14a //{{PADAUK_CODE_OPTION  .Code_Option Bootup  Slow  // 1024 ILRC  .Code_Option LVD  2.79V  // Maximum performance = 4 MIPS  .Code_Option Security Enable  // Security 3/4 words Enable //}}PADAUK_CODE_OPTION //定义I2C接口要用的IO口,用户可以自己修改这里的IO口定义 I2C_SDA equ pa.0 I2C_SDA_LOW equ set0 I2C_SDA I2C_SDA_HIGH equ set1 I2C_SDA I2C_SDA_INPUT equ set0 pac.0 I2C_SDA_OUTPUT equ set1 pac.0 I2C_SCL equ pa.4 //定义I2C设备地址,用户可以自己修改此地址 I2C_READ_CMD equ 0x7F I2C_WRITE_CMD equ 0x7E word init_timer //byte Xms //byte ms_cnt byte i2c_device //用来存放I2C接口地址 byte i2c_write_byte //I2C进行写操作时存放I2C写入的数据 byte i2c_read_byte //I2C进行读操作时候读出的内容 bit i2c_start_flag //应广单片机程序入口,第一条必须为跳转到第一个内核主程序入口地址的指令,第二条为第二个内核,有几个内核就有几条 .romadr 0x000  goto main0  goto main1 //应广单片机中断程序入口地址,所有中断共用同一个入口,需要用户自己判断中断类型 .romadr 0x010  pushaf //压栈  if(intrq.T16) //判断是否为定时中断  {   stt16 init_timer //清内部TIMER计数器   if(i2c_start_flag) //启动I2C通讯处理后这个标志会被置1   {    I2C_SDA_INPUT    reset //系统复位   }  }  intrq = 0 //清中断标志  popaf //弹栈  reti //中断返回 //---------------------------------------- //input: ms //用该函数可以再4M的频率下得到近似1毫秒的延时,在第一个内核中调用中断会导致延时加长 //---------------------------------------- /*delayXms:  while(Xms)  {   wdreset   ms_cnt = 20   while(ms_cnt)   {    delay 195    ms_cnt--   }   Xms--  }  ret*/ //用IO口模拟I2C slave模式的子函数 i2c_slave:  I2C_SDA_INPUT //将SDA设为输入 i2c_start:  //I2C空闲状态下SDA和SCL同为高电平,要启动I2C前初始状态必须是两者同为高  stt16 init_timer //清内部TIMER计数器  if(!I2C_SCL) //如果SCL为低,此时不用启动I2C通讯处理  {   goto i2c_stop  }  if(!I2C_SDA) //如果SDA为低,此时不用启动I2C通讯处理  {   goto i2c_stop  }  i2c_start_flag = 1 //启动I2C通讯处理,这个标志位会在定时中断中用到  //I2C的START信号是SDA和SCL同为高电平装态下SDA先变为低,然后SCL变为低  //判断I2C START信号  //等待SDA从高变低  stt16 init_timer //清内部TIMER计数器  wait0 I2C_SDA  //应广特有的等待IO变低指令,等待SDA从高变低,如果长时间没有变低,会触发定时中断,系统复位  nop //加适当延时消除IO抖动的影响  nop  nop  nop  //等待SCL从高变低,原理同上  stt16 init_timer  wait0 I2C_SCL  //if overtime MCU will auto reset  nop  nop  nop  nop  //已经判断为得到有效START信号  //开始接收I2C的器件地址,为了实现高速处理,程序顺序处理,没有使用循环处理方式  i2c_device = 0  stt16 init_timer  //device bit7  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.7  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit6  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.6  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit5  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.5  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit4  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.4  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit3  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.3  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit2  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.2  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit1  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.1  }  wait0 I2C_SCL  nop  nop  nop  nop  stt16 init_timer  //device bit0  wait1 I2C_SCL  nop  nop  nop  nop  if(I2C_SDA)  {   set1 i2c_device.0  }  wait0 I2C_SCL  //nop //后面的比较操作会耗费时间,可以不用延时  //nop  //nop  //nop  if(i2c_device == I2C_READ_CMD) //I2C进行读操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式  {   //回复slave ACK信号   I2C_SDA_OUTPUT   I2C_SDA_LOW   stt16 init_timer   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop     stt16 init_timer //i2c_read_byte bit7   if(i2c_read_byte.7)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit6   if(i2c_read_byte.6)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit5   if(i2c_read_byte.5)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit4   if(i2c_read_byte.4)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit3   if(i2c_read_byte.3)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit2   if(i2c_read_byte.2)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit1   if(i2c_read_byte.1)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_read_byte bit0   if(i2c_read_byte.0)   {    I2C_SDA_HIGH   }   else   {    I2C_SDA_LOW   }   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   I2C_SDA_INPUT   stt16 init_timer //master ack/nack   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   nop   nop   nop   nop   stt16 init_timer //END   wait1 I2C_SCL   nop   nop   nop   nop   stt16 init_timer   wait1 I2C_SDA   nop   nop   nop   nop  }  else if(i2c_device == I2C_WRITE_CMD) //I2C是进行写操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式  {   //slave ACK   I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------   I2C_SDA_LOW   stt16 init_timer   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   I2C_SDA_INPUT   i2c_write_byte = 0   stt16 init_timer //i2c_write_byte bit7   if(I2C_SDA)   {    set1 i2c_write_byte.7   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit6   if(I2C_SDA)   {    set1 i2c_write_byte.6   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit5   if(I2C_SDA)   {    set1 i2c_write_byte.5   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit4   if(I2C_SDA)   {    set1 i2c_write_byte.4   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit3   if(I2C_SDA)   {    set1 i2c_write_byte.3   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit2   if(I2C_SDA)   {    set1 i2c_write_byte.2   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit1   if(I2C_SDA)   {    set1 i2c_write_byte.1   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   stt16 init_timer //i2c_write_byte bit0   if(I2C_SDA)   {    set1 i2c_write_byte.0   }   nop   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   //slave NACK   I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------   I2C_SDA_HIGH   stt16 init_timer   wait1 I2C_SCL   nop   nop   nop   nop   wait0 I2C_SCL   //nop   //nop   //nop   //nop   I2C_SDA_INPUT //--------I2C SDA input/output switch----------   nop   nop   stt16 init_timer //END   wait1 I2C_SCL   nop   nop   nop   nop   stt16 init_timer   wait1 I2C_SDA   //nop   //nop   //nop   //nop   //下面代码用户可根据实际情况进行修改,这里是将I2C写入的数据取反后放到读操作位置   i2c_read_byte = ~i2c_write_byte    } i2c_stop:  I2C_SDA_INPUT  i2c_start_flag = 0 //I2C stop work  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.0 = 0 //pa.5 as GPIO  //注意IO口的输入输出设定  pa = 0b1111_1111  pac = 0b0000_0000  paph = 0b1111_1111  pb = 0b1111_1111  pbc = 0b0000_0000  pbph = 0b1111_1111  init_timer = 7768 //从7768进行校准为100ms  mov a,0b100_11_111  mov t16m,a  stt16 init_timer  delay 200  mov a,0  mov intrq,a  i2c_start_flag = 0 //I2C not start work // 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  set1 fppen.1 //eanble FPPA1  clkmd.1 = 1 //enable watch dog  wdreset //clear watch dog // Xms = 100 // call delayXms  stt16 init_timer  intrq = 0  inten.T16 = 1 //打开定时中断  engint main0_loop:  init_timer = 0  wdreset  //用户可以在这里添加自己想要的任意代码,这里可以实现任意一个普通单片机能够是想的功能  goto main0_loop //----------------FPPA1------------------- main1:  sp = 0x38 main1_loop:  call i2c_slave  goto main1_loop 程序中的多个NOP可以用 DELAY 3代替,用DELAY 指令可以节省程序空间    I2C启动判断代码用下面部分更可靠(2012.12.22) //wait SDA and SCL high at the same time  while((!I2C_SDA) || (!I2C_SCL))  {   stt16 init_timer   nop   nop   nop   nop  }  if(!I2C_SDA)  {   goto i2c_stop  }  if(!I2C_SCL)  {   goto i2c_stop  }  代码已编译,未调试  
  • 热度 20
    2012-12-20 21:03
    2827 次阅读|
    1 个评论
    本例是用针对标准I2C接口EEPROM存储器24C02进行读写操作,只要对例程做适当修改,就可以用到大部分控制I2C接口设备的场合。   //----------------------------------------- //应广单片机软件I2C接口例程(MASTER模式) //本例仅供参考,欢迎指正程序中的问题 //2012年12月20日 // //作者:戴上举 //邮箱:daishangju@163.com //博客:forum.eet-cn.com/BLOG_daishangju_334.HTM //电话:13509678051 //Q  Q:1514292225 //----------------------------------------- .chip p201cs14a //{{PADAUK_CODE_OPTION  .Code_Option Bootup  Slow  // 1024 ILRC  .Code_Option LVD  2.79V  // Maximum performance = 4 MIPS  .Code_Option Security Enable  // Security 3/4 words Enable //}}PADAUK_CODE_OPTION //定义I2C接口 I2C_SDA equ pa.7 I2C_SCL equ pa.6 I2C_SDA_DIR equ pac.7 I2C_SCL_DIR equ pac.6 I2C_LONG_DLY equ 50 I2C_SHORT_DLY equ 20 I2C_SDA_HIGH equ set1 I2C_SDA  I2C_SDA_LOW equ set0 I2C_SDA I2C_SCL_HIGH equ set1 I2C_SCL I2C_SCL_LOW equ set0 I2C_SCL I2C_SDA_OUTPUT equ set1 I2C_SDA_DIR I2C_SDA_INPUT equ set0 I2C_SDA_DIR I2C_SCL_OUTPUT equ set1 I2C_SCL_DIR I2C_SCL_INPUT equ set0 I2C_SCL_DIR //定义I2C变量 byte i2c_rw_addr //读写地址 byte i2c_rw_byte //读写数据 byte i2c_rw_cmd //读写的器件地址 byte i2c_rw_temp //读写过程中间变量 byte i2c_rw_cnt //读写过程中间变量 // byte Xms byte ms_cnt // byte test_addr byte test_data .romadr 0x000  goto main0  goto main1 .romadr 0x010 isr_entry:  pushaf  intrq = 0  popaf  reti //---------------------------- //产生START信号 //---------------------------- i2c_start:  I2C_SDA_OUTPUT  I2C_SCL_OUTPUT  I2C_SDA_HIGH  delay I2C_LONG_DLY  I2C_SCL_HIGH  delay I2C_LONG_DLY  I2C_SDA_LOW  delay I2C_LONG_DLY  I2C_SCL_LOW  delay I2C_LONG_DLY  ret //---------------------------- //产生STOP信号 //---------------------------- i2c_stop:  I2C_SCL_LOW  delay I2C_LONG_DLY  I2C_SDA_LOW  delay I2C_LONG_DLY  I2C_SCL_HIGH  delay I2C_LONG_DLY  I2C_SDA_HIGH  delay I2C_LONG_DLY  //  I2C_SCL_INPUT  I2C_SDA_INPUT  ret //---------------------------- //检查SALVE ACK信号 //---------------------------- i2c_slave_ack:  //don't check ACK  I2C_SDA_INPUT  delay I2C_SHORT_DLY  I2C_SCL_HIGH  delay I2C_SHORT_DLY  I2C_SCL_LOW  delay I2C_SHORT_DLY  I2C_SDA_OUTPUT  I2C_SDA_LOW  delay I2C_SHORT_DLY  ret //---------------------------- //输出MASTER ACK信号 //---------------------------- i2c_master_ack:  I2C_SDA_OUTPUT  I2C_SDA_LOW  delay I2C_SHORT_DLY  I2C_SCL_HIGH  delay I2C_SHORT_DLY  I2C_SCL_LOW  delay I2C_SHORT_DLY  ret //---------------------------- //输出MASTER NACK信号 //---------------------------- i2c_master_nack:  I2C_SDA_OUTPUT  I2C_SDA_HIGH  delay I2C_SHORT_DLY  I2C_SCL_HIGH  delay I2C_SHORT_DLY  I2C_SCL_LOW  delay I2C_SHORT_DLY  ret //------------------------------ //写一个字节 //Input: i2c_rw_temp //Used:  i2c_rw_cnt //------------------------------ i2c_write_8bit:  i2c_rw_cnt = 8 i2c_write_8bit_loop:  slc i2c_rw_temp  swapc I2C_SDA  delay I2C_SHORT_DLY  I2C_SCL_HIGH  delay I2C_SHORT_DLY  I2C_SCL_LOW  delay I2C_SHORT_DLY  dzsn i2c_rw_cnt  goto i2c_write_8bit_loop  ret //------------------------------ //读一个字节 //Used:   i2c_rw_cnt //Output: i2c_rw_temp //------------------------------ i2c_read_8bit:  i2c_rw_temp = 0  i2c_rw_cnt = 8  delay I2C_SHORT_DLY i2c_read_8bit_loop:  I2C_SCL_HIGH  delay I2C_SHORT_DLY  swapc I2C_SDA  slc i2c_rw_temp  I2C_SCL_LOW  delay I2C_SHORT_DLY  dzsn i2c_rw_cnt  goto i2c_read_8bit_loop  ret //------------------------------ //Input:  i2c_rw_addr //        i2c_rw_cmd //Used:   i2c_rw_cnt //        i2c_rw_temp //Output: i2c_rw_byte //------------------------------ i2c_read_byte:  //start  call i2c_start  //write device address(write)  i2c_rw_temp = i2c_rw_cmd  call i2c_write_8bit  //slave ack  call i2c_slave_ack  //write register address  i2c_rw_temp = i2c_rw_addr  call i2c_write_8bit  //slave ack  //don't check ACK  call i2c_slave_ack  //start repeat  call i2c_start  //write device address(read)  i2c_rw_temp = i2c_rw_cmd  i2c_rw_temp.0 = 1  call i2c_write_8bit  //slave ack  //don't check ACK  I2C_SDA_INPUT  delay I2C_SHORT_DLY  I2C_SCL_HIGH  delay I2C_SHORT_DLY  I2C_SCL_LOW  delay I2C_SHORT_DLY //这里为特殊情况I2C_SDA不用转为输出  //read data  i2c_rw_temp = 0  call i2c_read_8bit  i2c_rw_byte = i2c_rw_temp //store data  //master nack  call i2c_master_nack  //stop  call i2c_stop  //retune  delay I2C_LONG_DLY  wdreset  ret //------------------------------ //Input:  i2c_rw_addr //        i2c_rw_byte //        i2c_rw_cmd //Used:   i2c_rw_cnt //        i2c_rw_temp //------------------------------ i2c_write_byte:  //start  call i2c_start  //write device address  i2c_rw_temp = i2c_rw_cmd  call i2c_write_8bit  //slave ack  //don't check ACK  call i2c_slave_ack  //write register address  i2c_rw_temp = i2c_rw_addr  call i2c_write_8bit  //slave ack  //don't check ACK  call i2c_slave_ack  //write data  i2c_rw_temp = i2c_rw_byte  call i2c_write_8bit  //slave ack  //don't check ACK  call i2c_slave_ack  //stop  call i2c_stop  //retune  delay I2C_LONG_DLY  wdreset  ret EEPROM_RW_CMD equ 0xA0 //------------------------------ //函数名: eeprom_read_byte //Input:  i2c_rw_addr //Used:   i2c_rw_cnt //        i2c_rw_temp //Output: i2c_rw_byte //------------------------------ eeprom_read_byte:  i2c_rw_cmd = EEPROM_RW_CMD  goto i2c_read_byte //注意这里用的是跳转 //------------------------------ //函数名: eeprom_write_byte //Input:  i2c_rw_addr //        i2c_rw_byte //Used:   i2c_rw_cnt //        i2c_rw_temp //注意:  调用完后需要等待一段时间以保证写操作完成 //------------------------------ eeprom_write_byte:  i2c_rw_cmd = EEPROM_RW_CMD  goto i2c_write_byte //注意这里用的是跳转   //---------------------------------------- //input: ms //该函数以4M频率为基准时钟实现延时 //---------------------------------------- delayXms:  while(Xms)  {   wdreset   ms_cnt = 20   while(ms_cnt)   {    delay 195     ms_cnt--   }   Xms--  }  ret   main0:  .ADJUST_OTP_IHRCR 8MIPS  // IHRC/2 = 8MIPS, WatchDog Disable, RAM 0,1 temporary be used  sp = 0x30  disgint  inten = 0  pa = 0b0000_0000  paph = 0b1101_0000  pac = 0b0000_0001   pb = 0b0000_0000  pbph = 0b0000_0000  pbc = 0b1111_1111  I2C_SDA_INPUT  I2C_SCL_INPUT  delay 200  mov a,0b100_11_111  mov t16m,a  clkmd.1 = 1 //enable watch dog  wdreset  Xms = 100  call delayXms    test_data = 0  test_addr = 0 main0_loop:  wdreset  //写E2EPROM  i2c_rw_addr = test_addr  i2c_rw_byte = test_data  call eeprom_write_byte  //调用EEPROM写操作函数后要等待一段时间,以保证数据写操作完成  Xms = 20  call delayXms  //读E2EPROM  i2c_rw_addr = test_addr  call eeprom_read_byte  if(i2c_rw_byte != test_data)  {   //读回的数据比较出错,判断为读写E2PROM出错   nop  }  test_addr ++  test_data --    goto main0_loop //----------------FPPA1------------------- main1:   sp = 52 main1_loop:  goto main1_loop   本例代码是从实际程序中移植而来,已编译,未做最终调试
  • 热度 24
    2012-12-16 10:56
    4278 次阅读|
    9 个评论
    单片机工程师面对一种新单片机时,最希望的是能有一个简单的样例,这个样例连上仿真器就能运行,里面最好包含一些基本功能,这样工程师就可以在这个样例的基础上很快改出自己需要的代码。   这里我以应广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    已编译,未调试
  • 热度 25
    2011-3-16 21:44
    2898 次阅读|
    5 个评论
    经过一段时间的应用,感觉应广双核单片机在这些方面可以给大家一些提示。 1. 对C的支持相对有限,目前最主要的是不支持乘法(*)和除法(/),如果是想做一些运算的处理需要程序员自己编写相应程序,这样就对程序员的编程技能有一定要求。不过这只是编译器的不足,我相信假以时日应广的技术人员会在编译器中增加对乘法和除法操作符的支持。 (补充说明:现在应广的IDE工具已经支持乘除法,可以由IDE工具直接生成乘除法的汇编代码) 补充一句,台湾MCU厂商我个人感觉HOLTEK的C编译器最强,真的做得不错,就是MCU价格贵了点。 IDE自动生成的字节相乘代码: BYTE mul_y1, mul_x1; WORD mul_t2; void Byte_Mul_Byte (void) { // mul_t2 = mul_x1 * mul_y1  // 16  = 8  * 8  mul_t2$1 = 0;  BYTE cnt;  cnt = 8;  do  {   mul_x1 = 1;   if (CF)   {    mul_t2 += (mul_y1 8);   }   mul_t2 = 1;  } while (--cnt); } 2. 汇编和MINI_C都不区分大小写,会对习惯C程序风格的程序员产生小小的干扰。 3. 当电压低于3.3V时,对内部RC的影响会非常之大,我们实测结果是当电压为2.65V时,内部RC的频率已经变慢到3.3V的一半,需要注意的是这个测试和系统时钟的设定有一定关联。 我咨询应广台湾技术人员他们要求工作电压不得低于2.5V,实测结果是在2.5V以下芯片其实还能工作,就是速度变得很慢,我用少量芯片测试当电压降到2.0时芯片还在正常工作。(对于量产产品建议还是按应广产品手册要求设计供电电压范围) 4. ADC对采样电压点的输入阻抗要求偏高(芯片数据手册中已经提到此点),我们通过两个电阻分压测量电池电压,系统时钟为8M,ADC时钟为系统时钟16分频,如果用51k/39k,ADC结果不对,改为5.1k/3.9k才能得到正确结果。这个特性对需要高速AD测量并且是电池供电的设计有不良影响,如不做特殊处理待机状态下分压电阻会有几百微安得电流损耗。 5. 还是编译器的问题,目前MINI_C只支持无符号数,如果需要处理有符号数,还得需要程序员自己想拌饭。 6. 应广的MCU在待机电流方面做得还不错,我们实测结果是3.3V为0.65uA,2.5V为0.3uA。
相关资源
  • 所需E币: 0
    时间: 2022-3-15 02:32
    大小: 17.29MB
    上传者: samewell
    应广IC__带12位AD__MTP__价格低廉,_MFU121_Datasheet.pdf
  • 所需E币: 5
    时间: 2019-12-24 11:11
    大小: 882.99KB
    上传者: 978461154_qq
    你好,我司是台湾应广科技(Padauk)的一级代理商和各种电子方案设计的高科技公司,依托专业的技术和销售人员为客户提供最优质的产品和服务。代理台湾应广的工业级单片机,双内核,有带ADC,LCD驱动口,UART,PWM,可用汇编/C语言编程,开发工具卓越,工业级温度-40,搞干抗性达8KV。应广(Padauk)全系列MCU,http://www.szforsight.com/Products.htmlhttp://www.padauk.com.tw/咨询QQ:496438626TEL:13410553345……