说实话,AVR单片机挺好用,编程方便,稳定性也不错。自2005年以来,只要是项目允许就一直使用AVR单片机,自我感觉还算熟练。起码有很多现成的模块可以使用,组合起来实现功能也方便,但很多时候又是所谓的经验害死人。这次因智能营销机器人项目需要两个串口通信,也为日后升级方便,倒霉催的选择了ATmega324pa单片机,入坑开始,纯粹是所谓的经验害死人。1)AVR单片机有三个地方需要注意,第一个就是ATmega128引脚功能默认兼容ATmega103,这个需要使用关闭才能使用ATmega128的全部功能,并且其ISP口使用的是SPI而不是UART0,这个尤其需要当心;第二个就是需要关闭JTAG功能,否则引脚复用功能无法使用;第三个就是ATmega164,ATmega324和ATmega644等双串口单片机具有CKDIV8熔丝位,就是把内部时钟8分频的一个熔丝位,写串口通信时尤其当心这个熔丝位,害死人的。
2)作者以前使用ATmega8和ATmega16的TWI驱动DAC5571,非常好用,程序也非常简单,这次的智能营销机器人驱动板上也想当然的直接选用了DAC5571,电气原理图和封装直接拿过来使用,于是直接入坑。原来跑的及其欢快的程序卡壳了,编译很好,无任何警告信息,更无错误信息。使用UABASP烧入之后,根本就无电压输出,也没有出发设置的错误和报警警告。还把SZLCSC骂了很多时间,骂他们卖假货。查了很长时间,突然醒悟,不是我的程序出了问题吧? 查以前使用的twi.h,查DAC5571时序,没有问题啊,查熔丝位,也没有问题啊,这就fuck了。无奈之下,重新读代码也比较以前书写的代码,都无问题。那是什么问题? 买到假货了?SZLCSC不会这么干吧,兜兜转转之后重新审视自己的代码,最终定位在twi.h问题上。好吧,开干。这就是倒霉催的,放着好好的twi.h不用,非要自己写。这次使用WinAVR标配的twi.h头文件,重新写代码,注意DAC5571时序,先地址,再数据高位,最后数据低位,开工,两个DAC5571工作好的很。
当然了,这仅仅是DAC5571的测试代码,一个地址是0x98,一个是0x9A。
#include <avr/io.h>
#include <avr/power.h>
#include <util/delay.h>
#include <util/twi.h>
#define uint unsigned int
#define uchar unsigned char
//#define TWI_ADDRESS 0x98
//#define TWI_DATA 200
/*************主模式TWI 操作部分*************开始**************/
//总线上起动停止条件
void twi_stop(void)
{
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
}
//总线上起动开始条件
uchar twi_start(void)
{
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
while ((TWCR & _BV(TWINT)) == 0) ;
return TW_STATUS;
}
//写一字节
uchar twi_writebyte(uint c)
{
TWDR = c;
TWCR = _BV(TWINT) | _BV(TWEN);
while ((TWCR & _BV(TWINT)) == 0);
return TW_STATUS;
}
void twi_speed_set(uchar uaddress, uchar udatain)
{
twi_start();
twi_writebyte(uaddress);
twi_writebyte(udatain>>4);
twi_writebyte((udatain<<4) & 0xf0);
twi_stop();
}
int main(void)
{
//便能 SCL、SDA 引脚内部上拉电阻
DDRC=(0<<PC0) | (0<<PC1);
PORTC=(1<<PC0) | (1<<PC1);
power_twi_enable();
TWSR=0x00;
TWBR=0x20;
TWAR=0x00;
TWCR=0x04;
twi_speed_set(0x9A,50);
_delay_ms(30);
twi_speed_set(0x98,150);
while(1);
return 1;
}
|