如何烧录 arduino 的 bootloader?

如何烧录 arduino 的 bootloader?,第1张

为了恢复Arduino的功能,必须得重新给ATMega328P单片机里烧写bootloader(其实Arduino就是在AVR单片机中胡答预置了一个bootloader程序,这样再配合Arduino开发环境就是所谓的Arduino了,但Arduino这个词本身只留给官方使用)。当然在淘宝上也能买到已经烧写好的AVR单片机,只是自己手上已经有了AVR单片机,就没必要去花那冤枉钱了。

于是马上打开万能的百度,输入关键字“Arduino bootloader”果然,一大堆乱七八糟相关的问题就出来了,经过一轮的筛选,发现许多说的也并不是很清晰,不过让我明白了个大概:一个普通的AVR单片机确实能烧写bootloader之后作为Arduino使用。那么问题来了,如何把bootloader烧录到AVR单片机中去了?这的确是个问题,反正对于不懂AVR开发的我来说是个问题。不过还好之前在淘宝上买了一个USBASP下载器,跟之前擦除bootloader一样,也要用到progisp软件(因为此时的ATMega328P只是一枯埋个普通的AVR单片机,用Arduino开发软件是烧写不进去的)。

既然要烧没做蚂录bootloader,那么什么是bootloader呢?正如你所想,bootloader当然是一个程序,既然要烧录到单片机中去,应该是一个.HEX之类的文件。但是,bootloader文件从哪来呢?继续百度。。。找到了,在Arduino软件安装目录中的hardware\arduino中。此文件夹下的“boards.txt”文件很重要,是很重要,其他的或许都可以在百度上找到,但因为这个文件折腾了我大半个晚上,百度上也没有明确的说明。打开文件,找到自己对应的Arduino版本,因为我的是“Arduino Uno”,于是锁定“uno.name=Arduino Uno”区域的说明,因为看上去很乱,一定要仔细去看。找到“uno.bootloader.low_fuses=0xff"指编程熔丝低位为FF,”uno.bootloader.high_fuses=0xde“指编程熔丝高位为DE,”uno.bootloader.extended_fuses=0x05“指扩展位为05。这三个值非常重要,是决定你烧录bootloader成功的关键。至于这三个值具体是什么意思,我也不是很不清楚,但AVR单片机的烧录时需要设置熔丝位,而且不能乱设置,这也是AVR跟51单片机的不同之处。

用progisp软件把这三个熔丝位的值写入到AVR单片机中,然后继续浏览”boards.txt“文件往下看,找到”uno.bootloade旦长测短爻的诧痊超花r.path=optiboot“这就是说要烧录的bootloader文件在bootloaders\option文件夹中,“uno.bootloader.file=optiboot_atmega328.hex”文件名就是optiboot_atmega328.hex,这就是接下来需要烧录到AVR单片机中的程序。用progisp软件调入此文件,然后直接写入到AVR单片机中就行了,一个支持Arduino的AVR就做好了。。。

其实这个问题本身不难,但对于没接触过AVR的人来说,还是要花许多时间的,中间也会存在许许多多各种各样的问题。至于progisp的使用方法很简单,百度上的教程也很多,还有手上必须有一块可以烧录AVR单片机的下载器。我当时就是忽略了那三个熔丝位的值,所以反反复复也没有成功,百度上面也没有对”boards.txt“文件做详细的解释。没设置熔丝位程序是可以正常的烧录进去,但Arduino是不能用的,所以必须要按照官网给出的说明 *** 作。我当时大多数时间主要花在两个问题上,一个是.HEX文件具体位置,因为Arduino有不同的版本,所以.HEX文件也不同,还有一个就是熔丝位上。

Uno单片机不是51单片机,它采用的是ATmega328P微控制器,是一种基于AVR指令集架构的单片机芦橘。Uno单片机主要由Atmel公司开发和生产,并通过Arduino平台得以广泛应用。

而51单片机指的是指基于Intel 8051芯片架构设计的单片机,是在上世纪80年代被广泛采用的单睁野片机之一,在嵌入式系统开发领域有着广泛的应用。

虽然Uno单片机和51单片机都是常见的单片机,但它们的内核架构和指令集都不同,因此它们适用的开发软件、编译环境和支悉哗喊持库也不同,需要针对具体的单片机选择和编写相应的程序代码和支持软件。

/*========================================================

片外16Mhz晶体振荡器,AT24C04 A0,A1,A2接地处理

WP接地处理,器件读地址为0xA0。串口波特率9600,无校验。

mega328 SRAM为2048个字节

---2016/5/4 小怪

===============================================================*/

#include <avr\pgmspace.h>

#define AT24C_Add_W 0xA0 //器件读地址,A2,A1=0, 默认选择0~255字节地址

#define AT24C_Add_R 0xA1 //器件写地址,A2,A1=0, 默认选择0~255字节地址

#define SLAW 0x18 //模块正确地址应答常量写 page200

#define DataOKW 0x28 //模块正确数据写应答常量

#define SLAR 0x40 //地址收到ok,page204

#define DataOKR 0x50 //数据收到ok

//数据类型宏定义

typedef unsigned char uint08

typedef signed char sint08

typedef unsigned int uint16

typedef signed int sint16

//变量定义

//发送数据缓存区,存入FLASH ,ASCII码形式,不支持隐衡中兄携旦文,注意在字符羡扰串尾加0xFF作为结束标记

const PROGMEM uint08 Send_Buff[512]="As food is to the body, so is learning to the mind. Our bodies grow and muscles develop with the intake of adequate nutritious food. Likewise, we should keep learning day by day to maintain our keen mental power and expand our intellectual capacity. Constant learning supplies us with inexhaustible fuel for driving us to sharpen our power of reasoning, analysis, and judgment. Learning incessantly is the surest way to keep pace with the times in the information age\xFF"

uint08 Page=0x00//页选择位,选择0或1,选择0页写0,选择1页写2

uint08 Read_Buff[512] //数据接收缓存区,AT24C04最大空间256字节

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

//AT24时钟频率1Mhz,设置单片机比特率

//SCL frequency=cpu clock/(16+2(TWBR)*(prescalerValue))

void Init_TWI(void)

{ TWCR = 0x00 //中止IIC

//PRR = 0x00//复位功耗抑制寄存器,TWI唤醒

TWBR = 24 //比特率寄存器为24,产生9615波特率

TWSR|= 0x02 //比特率预分频因子16,page194

//TWAR=0xFF //工作于主机模式不需要此地址

TWCR = (1<<TWEN) //TWI使能,TWINF写1清零

}

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

//启动I2C

void TWIStart(void) //page198

{ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)//TWI start,主机模式,page149

while(!(TWCR&(1<<TWINT))) //等待TWINF置位以及收到应答信号

}

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

//主机发送一个字节

void TWI_Write(uint08 str)

{ TWDR = str //将字符写入数据寄存器

TWCR = (1<<TWINT)|(1<<TWEN) //启动发送地址及数据,page198

while(!(TWCR&(1<<TWINT))) //等待TWINF置位,SLA+W或data已发出

}

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

//总线读出一个字符返回读出的字符

uint08 TWI_READ(void)

{ TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN)

while(!(TWCR&(1<<TWINT)))

return(TWDR) //返回读出的数据

}

//I2C应答函数-------------------------------------------------------------------

uint08 TWI_ACK(void)

{ _NOP() //延时1个指令周期

return (TWSR&0xF8) //返回TWI状态,高5位

}

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

//I2C 停止

void TWI_Stop(void)

{

TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN) //page198

}

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

//向I2C slave写入数据,第一个参数是页选择为0和1。第二个是字节地址0xFF,第三个参数为字节数据

void AT24_TWI_Write(uint08 Page,uint08 ByteAdd,uint08 Str)

{ TWIStart()//开启发送

TWI_Write(Page|AT24C_Add_W) //发送从机地址

if(TWI_ACK()==SLAW)//应答

TWI_Write(ByteAdd) //发送字节地址

if(TWI_ACK()==DataOKW)//应答

TWI_Write(Str) //发送数据

TWI_ACK() //写入数据应答

TWI_Stop()//发送停止信号

delay(1) //延时1ms,完成写入

}

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

//从I2C读取数据参数1为变量地址,参数2为页选择,参数3为字节地址,参数4为读取数量

//读取模式为随机读

uint08 AT24_TWI_Read(uint08 Page,uint08 ByteAdd)

{ uint08 i,u08temp

TWIStart() //发送起始信号

TWI_Write(Page|AT24C_Add_W)//写入地址及页选择位

if(TWI_ACK()==SLAW) //地址发送应答

TWI_Write(ByteAdd) //写入字节地址

if(TWI_ACK()==DataOKW) //发送页码和字节地址

TWIStart() //再一次开始

TWI_Write(Page|AT24C_Add_R) //写入读地址及页选择位

if(TWI_ACK()==SLAR)//读应答,返回值有误

TWI_ACK()

u08temp=TWI_READ()//从总线读一个字节存入中间量

TWI_ACK() //应答

TWI_Stop()//发送停止信号

return u08temp//返回读取的数据

}

//写入数据函数------------------------------------------------------------------

void WriteAT24(const uint08 ch[])

{ uint16 u16add=0

uint08 ByteAdd//字节起始地址

uint08 u08temp

Page=0

for(ByteAdd=0u16add++,ByteAdd++)

{

u08temp=pgm_read_byte_near(ch+u16add)

if(u08temp==0xff) return

if(ByteAdd<0xff) //如果长度小于255则写入第一页

AT24_TWI_Write(Page,ByteAdd,u08temp) //向AT24C04写入数据

else

{

AT24_TWI_Write(Page,ByteAdd,u08temp) //向AT24C04写入数据

if(!Page)Page=0x02 //换页

else return

ByteAdd=0

}

}

}

//读入数据函数------------------------------------------------------------------

void ReadAt24( uint08 ch[])

{uint08 u08tempt

uint16 u16add

uint08 ByteAdd=0//字节起始地址

Page=0

for(u16add=0u16add++,ByteAdd++)

{

u08tempt=AT24_TWI_Read(Page,ByteAdd) //读一个字节

if(u08tempt==0xff) break //返回字符为0xff提前结束

if(ByteAdd<0xff) ch[u16add]=u08tempt

else

{ ch[u16add]=u08tempt

if(!Page) Page=2

else return

ByteAdd=0

}

}

}

//======================================================================

void WDT_OFF(void)

{WDTCSR|=0x80

MCUSR&=~(1<<WDRF)

WDTCSR |= (1<<WDCE) | (1<<WDE)

WDTCSR = 0x00

}

//======================================================================

void setup(void )

{

cli() //清中断

Init_TWI()//初始化设备

WDT_OFF() //关闭看门狗

Serial.begin(9600)

sei() //中断使能

WriteAT24(Send_Buff) //写数据

}

//主函数------------------------------------------------------------------------

void loop(void)

{

// WDTCSR|=0x80

ReadAt24(Read_Buff)

//Serial.println("have read data:")

Serial.println((char*)Read_Buff) //串口发送读到的数据

delay(1000) //延时1s

}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12462035.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存