使用Arduino作为ISP编程器为AVR芯片烧录Bootloader的完整指南
2026/7/29 6:25:52
//ADC自校准 int ADC1_calibration(void) { ADC1->GC |= (1<<7); while((ADC1->GC & (1<<7)) != 0); if((ADC1->GS & (1<<1)) == 0) { return 1; } else { return 0; } } //ADC初始化 void ADC1_channel1_init(void) { //引脚复用 IOMUXC_SetPinMux(IOMUXC_GPIO1_IO01_GPIO1_IO01,0); //电气属性 IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01,IOMUXC_SW_PAD_CTL_PAD_PKE(1)); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01,IOMUXC_SW_PAD_CTL_PAD_PUE(0)); //配置ADC ADC1->HC[0] &= ~(1<<7); ADC1->CFG = 0; ADC1->CFG |= (2<<2) | (3<<0); ADC1->GC = 0; ADC1->GC |= (1<<0); //ADC校准 printf(ADC1_calibration()?"calibration completed normally!\n" : "calibration completed failed!\n"); } //读取ADC原始值 unsigned short ADC1_get_origin_value(void) { //启动ADC转换 ADC1->HC[0] = 0; ADC1->HC[0] = 1; //等待ADC转换完成 while ((ADC1->HS & (1<<0)) == 0); //读取ADC原始值 return ADC1->R[0] & 0xFFF; } void sort(unsigned short *a,int len) { int i = 0; int j = 0; int temp = 0; for (i = 0; i < len; i++) { for(j = i+1 ;j < len;j++) { if(a[i] > a[j]) { temp = a[i]; a[i] = a[j]; a[j] = temp; } } } } //ADC采样值求和 unsigned int sum_of_array(unsigned short *a,int len) { unsigned int sum=0; int i=0; for(i=0;i<len;i++) { sum += a[i]; } return sum; } //读取ADC电压值 float ADC1_get_value(void) { unsigned short a[100]; int i=0; for(i=0;i<=100;i++) { a[i]=ADC1_get_origin_value(); } sort(a,sizeof(a)/sizeof(a[0])); return sum_of_array(a+10,80) / 80 /4095.0 * 3.3; }概括为:
BURST_LENGTH(bit31:20):突发长度,设置 SPI 的突发传输数据长度,在一次 SPI 发送中最大可以 发送 2^12bit 数据。可以设置 0X000~0XFFF,分别对应 1~2^12bit。我们一般设置突发长度为一个 字节,也就是 8bit,BURST_LENGTH=7; CHANNEL_SELECT(bit19:18):SPI 通道选择,一个 ECSPI 有四个硬件片选信号,每个片选信号是一个 硬件通道,刚才查看了I.MX6U-ALPHA 开发板上的 ICM-20608 的片选信号接的是ECSPI3_SS0,也就是 ECSPI3 的通道 0,所以本实验设置为 0; DRCTL(bit17:16):SPI 的 SPI_RDY 信号控制位,用于设置 SPI_RDY 信号,为 0 的话不关心SPI_RDY 信 号;为 1 的话 SPI_RDY 信号为边沿触发;为 2 的话 SPI_DRY 是电平触发。 SPI_DRY 决定了如何启动一 次数据传输,手册第796页有SPI_RDY 的详细说明; PRE_DIVIDER(bit15:12):SPI 预分频,ECSPI 时钟频率使用两步来完成分频,此位设置的是第一步,可 设置 0~15,分别对应 1~16 分频。从时钟树可以看出,ECSPI时钟源是pll3_sw_clk = 480MHz,经过一 个8分频的静态分频器,实际工作频率是60MHz; POST_DIVIDER(bit11:8):SPI 分频值,ECSPI 时钟频率的第二步分频设置,分频值为2^POST_DIVIDER; CHANNEL_MODE(bit7:4):SPI 通道主/从模式设置,CHANNEL_MODE[3:0]分别对应 SPI通道 3~0, 为 0 的话就是设置为从模式,如果为 1 的话就是主模式。比如设置为 0X01 的话就是设置通道 0 为主模 式; SMC(bit3):开始模式控制,此位只能在主模式下起作用,为 0 的话通过 XCH 位来开启 SPI突发访问, 为 1 的话只要向 TXFIFO 写入数据就开启 SPI 突发访问; XCH(bit2):此位只在主模式下起作用,当 SMC 为 0 的话此位用来控制 SPI 突发访问的开启; HT(bit1):HT 模式使能位,I.MX6ULL 不支持; EN(bit0):SPI 使能位,为 0 的话关闭 SPI,为 1 的话使能 SPI。HT_LENGTH(bit28:24):HT 模式下的消息长度设置,I.MX6ULL 不支持; SCLK_CTL(bit23:20):设置 SCLK 信号线空闲状态电平,SCLK_CTL[3:0]分别对应通道3~0,为 0 的话 SCLK 空闲状态为低电平,为 1 的话 SCLK 空闲状态为高电平; DATA_CTL(bit19:16):设置 DATA 信号线空闲状态电平,DATA_CTL[3:0]分别对应通道3~0,为 0 的话 DATA 空闲状态为高电平,为 1 的话 DATA 空闲状态为低电平; SS_POL(bit15:12):设置 SPI 片选信号极性设置,SS_POL[3:0]分别对应通道 3~0,为 0 的话片选信号 低电平有效,为 1 的话片选信号高电平有效; SCLK_POL(bit7:4):SPI 时钟信号极性设置,也就是 CPOL,SCLK_POL[3:0]分别对应通道 3~0,为 0 的 话 SCLK 高电平有效(空闲的时候为低电平),为 1 的话 SCLK 低电平有效(空闲的时候为高电平); SCLK_PHA(bit3:0):SPI时钟相位设置,也就是CPHA,SCLK_PHA[3:0]分别对应通道3~0,为 0 的话串 行时钟的第一个跳变沿(上升沿或下降沿)采集数据,为 1 的话串行时钟的第二个跳变沿(上升沿或下降沿) 采集数据。CSD_CTL(bit21:16):片选信号延时控制位,用于设置片选信号和第一个 SPI 时钟信号之间的时间间隔, 范围为 0~63; CSRC(bit15):SPI 时钟源选择,为 0 的话选择 SPI CLK 为 SPI 的时钟源,为 1 的话选择32.768KHz 的 晶振为 SPI 时钟源。我们一般选择 SPI CLK 作为 SPI 时钟源; SPI CLK 的时钟频率为60MHz,从在时钟 树上对应的是ECSPI_CLK_ROOT,该时钟将pll3_sw_clk经由静态8分频之后到达一个选通器,由CSCDR2 的ECSPI_CLK_SEL决定,我们肯定是选择60MHz,再经过CSCDR2的ECSPI_CLK_PODF进行分频,我们 配置为0,选择SPI CLK。 SAMPLE_PERIO(bit14:0):采样周期寄存器,可设置为 0~0X7FFF 分别对应 0~32767 个周期。 接下来看一下寄存器 ECSPIx_STATREG,这个是 ECSPI 的状态寄存器 TC(bit7):传输完成标志位,为 0 表示正在传输,为 1 表示传输完成; RO(bit6):RXFIFO 溢出标志位,为 0 表示 RXFIFO 无溢出,为 1 表示 RXFIFO 溢出; RF(bit5):RXFIFO 空标志位,为 0 表示 RXFIFO 不为空,为 1 表示 RXFIFO 为空; RDR(bit4):RXFIFO 数据请求标志位,此位为 0 表示 RXFIFO 里面的数据不大于RX_THRESHOLD,此 位为 1 的话表示 RXFIFO 里面的数据大于 RX_THRESHOLD; RR(bit3):RXFIFO 就绪标志位,为 0 的话 RXFIFO 没有数据,为 1 的话表示 RXFIFO 中至少有一个字的 数据。 TF(bit2):TXFIFO 满标志位,为 0 的话表示 TXFIFO 不为满,为 1 的话表示 TXFIFO 为满; TDR(bit1):TXFIFO 数据请求标志位,为 0 表示 TXFIFO 中的数据大于 TX_THRESHOLD,为 1 表示 TXFIFO 中的数据不大于 TX_THRESHOLD; TE(bit0):TXFIFO 空标志位,为 0 表示 TXFIFO 中至少有一个字的数据,为 1 表示 TXFIFO为空。//SPI3初始化 void spi3_init(void) { //引脚复用 IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0); IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0); IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0); IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0); //电气属性 IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0x10B1); IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0x10B1); //通信前,先将CS拉高 GPIO1->GDIR |= (1<<20); GPIO1->DR |= (1<<20); //CONREG ECSPI3->CONREG = 0; ECSPI3->CONREG |= (7<<20) | (0x0E<<12) | (2<<8) | (1<<4) | (1<<3) | (1<<0); //CONFIGREG ECSPI3->CONFIGREG = 0; ECSPI3->CONFIGREG |= (1<<20) | (1<<4) | (1<<0); } //SPI读写函数 unsigned int spi3_read_write(unsigned int data) { while((ECSPI3->STATREG & (1<<0)) == 0); ECSPI3->TXDATA = data; while((ECSPI3->STATREG & (1<<3)) == 0); return ECSPI3->RXDATA; }void adxl345_write(unsigned char reg_address,unsigned char data) { //片选拉低 GPIO1->DR &= ~(1<<20); //发送寄存器地址 spi3_read_write(reg_address); //发送写入的数据 spi3_read_write(data); //片选拉高 GPIO1->DR |= (1<<20); } unsigned char adxl345_read(unsigned char reg_address) { unsigned char ret=0; //片选拉低 GPIO1->DR &= ~(1<<20); //发送寄存器地址 spi3_read_write(reg_address | 0x80); //发送占位字节 ret = spi3_read_write(0xFF); //片选拉高 GPIO1->DR |= (1<<20); return ret; } //ADXL345初始化 void adxl345_init(void) { //关闭中断 adxl345_write(0x2E,0x08); //满分辨率13位 adxl345_write(0x31,0x0B); //速率25HZ adxl345_write(0x2C,0x08); //工作模式 adxl345_write(0x2D,0x0B); } struct ADXL345_Data adxl345_get_value(void) { struct ADXL345_Data ret; //x轴数据 ret.x = adxl345_read(0x32); ret.x |= adxl345_read(0x33)<<8; //y轴数据 ret.y = adxl345_read(0x34); ret.y |= adxl345_read(0x35)<<8; //z轴数据 ret.z = adxl345_read(0x36); ret.z |= adxl345_read(0x37)<<8; ret.xg = ret.x * 0.0039; ret.yg = ret.y * 0.0039; ret.zg = ret.z * 0.0039; return ret; }#ifndef _ADXL345_H_ #define _ADXL345_H_ struct ADXL345_Data { short x; short y; short z; float xg; float yg; float zg; }; extern void adxl345_write(unsigned char reg_address,unsigned char data); extern unsigned char adxl345_read(unsigned char reg_address); extern void adxl345_init(void); extern struct ADXL345_Data adxl345_get_value(void); #endifint main(void) { //时钟初始化 clock_init(); // 初始化 system_interrupt_init(); beep_init(); led_init(); //key_init(); //epit_init(); gpt_init(); uart_init(); I2C_init(); //ADC1_channel1_init(); spi3_init(); adxl345_init(); led_off(); beep_off(); //unsigned char t=adxl345_read(0x00); //printf("adxl345_ID:%x\n",t); while (1) { struct ADXL345_Data t=adxl345_get_value(); int i,j,k; i = t.xg * 10; j = t.yg * 10; k = t.zg * 10; printf("x_accel:%d.%d y_accel:%d.%d z_accel:%d.%d\n",i / 10,i % 10,j / 10,j % 10,k / 10,k % 10); delay_ms(1000); } return 0; }