- 打卡等级:以坛为家I
- 打卡总天数:274
- 最近打卡:2026-07-21 08:44:27
已绑定手机
超级版主
- 积分
- 3313

|
66-DMA-I2C主机模式读写AT24C02-串口监控,AI8051U实验箱演示程序
主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com -----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序 */
/*---------------------------------------------------------------------*/
/************* 功能说明 **************
本例程基于AI8051U为主控芯片的实验箱进行编写测试。
使用Keil C51编译器,为了达到比较高的效率,一般建议选择"Small"模式。
当编译器出现 "error C249: 'DATA': SEGMENT TOO LARGE" 错误时,则需要手动将部分比较大的数组通过"xdata" 强制分配到 XDATA 区域(例如: char xdata buffer [256];)
串口发指令通过I2C DMA读写AT24C02数据.
串口(P3.0,P3.1)默认设置: 115200,8,N,1.
串口命令设置: (字母不区分大小写)
W 0x10 12345678 --> 写入操作 十六进制地址 写入内容.
R 0x10 8 --> 读出操作 十六进制地址 读出字节数.
24CXX连续写入的字节数不同, 1\2Kbit 8-Byte/Page, 4\8\16Kbit 16-Byte/Page.
连续写入的话,地址+数据长度不要超过一个PAGE范围.
下载时, 选择时钟 22.1184MHz (用户可自行修改频率).
******************************************/
#include "../comm/AI8051U.h"
#include "intrins.h"
#include "stdio.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/****************************** 用户定义宏 ***********************************/
#define MAIN_Fosc 22118400L //定义主时钟(精确计算115200波特率)
#define Baudrate 115200L
#define TM (65536 -(MAIN_Fosc/Baudrate/4))
/*****************************************************************************/
/************* 本地常量声明 **************/
#define EE_BUF_LENGTH 255 //
#define UART1_BUF_LENGTH (EE_BUF_LENGTH+7) //串口缓冲长度
#define SLAW 0xA0
#define SLAR 0xA1
/************* 本地变量声明 **************/
u8 EEPROM_addr;
u8 xdata DmaTxBuffer[256];
u8 xdata DmaRxBuffer[256];
u8 RX1_TimeOut;
u16 RX1_Cnt; //接收计数
bit B_TX1_Busy; //发送忙标志
bit DmaTxFlag=0;
bit DmaRxFlag=0;
u8 RX1_Buffer[UART1_BUF_LENGTH]; //接收缓冲
/************* 本地函数声明 **************/
void I2C_init(void);
void WriteNbyte(u8 addr, u8 number);
void ReadNbyte( u8 addr, u8 number);
void delay_ms(u8 ms);
void RX1_Check(void);
void DMA_Config(void);
/******************** 串口打印函数 ********************/
void UartInit(void)
{
P_SW1 &= ~S1_S1; //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
P_SW1 &= ~S1_S0;
SCON = (SCON & 0x3f) | 0x40;
AUXR |= (1<<6); //定时器时钟1T模式
AUXR &= ~S1BRT; //串口1选择定时器1为波特率发生器
TL1 = TM;
TH1 = TM>>8;
TR1 = 1; //定时器1开始计时
// SCON = (SCON & 0x3f) | 0x40;
// T2L = TM;
// T2H = TM>>8;
// AUXR |= 0x15; //串口1选择定时器2为波特率发生器
REN = 1; //允许接收
ES = 1; //使能串口1中断
}
void UartPutc(unsigned char dat)
{
SBUF = dat;
B_TX1_Busy = 1;
while(B_TX1_Busy);
}
char putchar(char c)
{
UartPutc(c);
return c;
}
/**********************************************/
void main(void)
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXSFR(); //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
I2C_init();
UartInit();
DMA_Config();
EA = 1; //允许总中断
printf("命令设置:\r\n");
printf("W 0x10 12345678 --> 写入操作 十六进制地址 写入内容\r\n");
printf("R 0x10 8 --> 读出操作 十六进制地址 读出字节内容\r\n");
while(1)
{
delay_ms(1);
if(RX1_TimeOut > 0)
{
if(--RX1_TimeOut == 0) //超时,则串口接收结束
{
if(RX1_Cnt > 0)
{
RX1_Check(); //串口1处理数据
}
RX1_Cnt = 0;
}
}
}
}
//========================================================================
// 函数: void delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-3-9
// 备注:
//========================================================================
void delay_ms(u8 ms)
{
u16 i;
do{
i = MAIN_Fosc / 6000;
while(--i);
}while(--ms);
}
/**************** ASCII码转BIN ****************************/
u8 CheckData(u8 dat)
{
if((dat >= '0') && (dat <= '9')) return (dat-'0');
if((dat >= 'A') && (dat <= 'F')) return (dat-'A'+10);
return 0xff;
}
/**************** 获取写入地址 ****************************/
u8 GetAddress(void)
{
u8 address;
u8 i,j;
address = 0;
if((RX1_Buffer[2] == '0') && (RX1_Buffer[3] == 'X'))
{
for(i=4; i<6; i++)
{
j = CheckData(RX1_Buffer);
if(j >= 0x10) return 0; //error
address = (address << 4) + j;
}
return (address);
}
return 0; //error
}
/**************** 获取要读出数据的字节数 ****************************/
u8 GetDataLength(void)
{
u8 i;
u8 length;
length = 0;
for(i=7; i<RX1_Cnt; i++)
{
if(CheckData(RX1_Buffer) >= 10) break;
length = length * 10 + CheckData(RX1_Buffer);
}
return (length);
}
/**************** 串口处理函数 ****************************/
void RX1_Check(void)
{
u8 i,j;
F0 = 0;
if((RX1_Cnt >= 8) && (RX1_Buffer[1] == ' ')) //最短命令为8个字节
{
for(i=0; i<6; i++)
{
if((RX1_Buffer >= 'a') && (RX1_Buffer <= 'z')) RX1_Buffer = RX1_Buffer - 'a' + 'A';//小写转大写
}
EEPROM_addr = GetAddress();
if(EEPROM_addr <= 255)
{
if((RX1_Buffer[0] == 'W') && (RX1_Cnt >= 8) && (RX1_Buffer[6] == ' ')) //写入N个字节
{
j = RX1_Cnt - 7;
for(i=0; i<j; i++) DmaTxBuffer[i+2] = RX1_Buffer[i+7];
WriteNbyte(EEPROM_addr, j); //写N个字节
printf("已写入%d字节内容!\r\n",j);
delay_ms(5);
ReadNbyte(EEPROM_addr, j);
printf("读出%d个字节内容如下:\r\n",j);
for(i=0; i<j; i++) printf("%c", DmaRxBuffer);
printf("\r\n");
F0 = 1;
}
else if((RX1_Buffer[0] == 'R') && (RX1_Cnt >= 8) && (RX1_Buffer[6] == ' ')) //读出N个字节
{
j = GetDataLength();
if((j > 0) && (j <= EE_BUF_LENGTH))
{
ReadNbyte(EEPROM_addr, j);
printf("读出%d个字节内容如下:\r\n",j);
for(i=0; i<j; i++) printf("%c", DmaRxBuffer);
printf("\r\n");
F0 = 1;
}
}
}
}
if(!F0) printf("命令错误!\r\n");
}
//========================================================================
// 函数: void DMA_Config(void)
// 描述: I2C DMA 功能配置.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2021-5-6
//========================================================================
void DMA_Config(void)
{
DMA_I2CT_STA = 0x00;
DMA_I2CT_CFG = 0x80; //bit7 1:Enable Interrupt
DMA_I2CT_AMT = 0xff; //设置传输总字节数(低8位):n+1
DMA_I2CT_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_I2CT_TXAH = (u8)((u16)&DmaTxBuffer >> 8); //I2C发送数据存储地址
DMA_I2CT_TXAL = (u8)((u16)&DmaTxBuffer);
DMA_I2CT_CR = 0x80; //bit7 1:使能 I2CT_DMA, bit6 1:开始 I2CT_DMA
DMA_I2CR_STA = 0x00;
DMA_I2CR_CFG = 0x80; //bit7 1:Enable Interrupt
DMA_I2CR_AMT = 0xff; //设置传输总字节数(低8位):n+1
DMA_I2CR_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_I2CR_RXAH = (u8)((u16)&DmaRxBuffer >> 8); //I2C接收数据存储地址
DMA_I2CR_RXAL = (u8)((u16)&DmaRxBuffer);
DMA_I2CR_CR = 0x81; //bit7 1:使能 I2CT_DMA, bit5 1:开始 I2CT_DMA, bit0 1:清除 FIFO
DMA_I2C_ST1 = 0xff; //设置需要传输字节数(低8位):n+1
DMA_I2C_ST2 = 0x00; //设置需要传输字节数(高8位):n+1
}
//========================================================================
// 函数: void UART1_int (void) interrupt UART1_VECTOR
// 描述: UART1中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_int (void) interrupt 4
{
if(RI)
{
RI = 0; //Clear Rx flag
RX1_Buffer[RX1_Cnt] = SBUF;
if(++RX1_Cnt >= UART1_BUF_LENGTH) RX1_Cnt = 0;
RX1_TimeOut = 5;
}
if(TI)
{
TI = 0; //Clear Tx flag
B_TX1_Busy = 0;
}
}
/********************** I2C函数 ************************/
void I2C_init(void)
{
P_SW2 = (P_SW2 & ~(3<<4)) | (3<<4); //IO口切换. 0: P1.4 P1.5, 1: P2.4 P2.5, 3: P3.3 P3.2
I2CCFG = 0xe0; //使能I2C主机模式
I2CMSST = 0x00;
}
void WriteNbyte(u8 addr, u8 number) /* WordAddress,First Data Address,Byte lenth */
{
while(I2CMSST & 0x80); //检查I2C控制器忙碌状态
DmaTxFlag = 1;
DmaTxBuffer[0] = SLAW;
DmaTxBuffer[1] = addr;
I2CMSST = 0x00;
I2CMSCR = 0x89; //set cmd //write_start_combo
DMA_I2C_CR = 0x01;
DMA_I2CT_AMT = number+1; //设置传输总字节数(低8位):number + 设备地址 + 存储地址
DMA_I2CT_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_I2C_ST1 = number+1; //设置需要传输字节数(低8位):number + 设备地址 + 存储地址
DMA_I2C_ST2 = 0x00; //设置需要传输字节数(高8位):n+1
DMA_I2CT_CR |= 0x40; //bit7 1:使能 I2CT_DMA, bit6 1:开始 I2CT_DMA
while(DmaTxFlag); //DMA忙检测
DMA_I2C_CR = 0x00;
}
void ReadNbyte(u8 addr, u8 number) /* WordAddress,First Data Address,Byte lenth */
{
while(I2CMSST & 0x80); //检查I2C控制器忙碌状态
DMA_I2C_CR = 0x00;
I2CMSST = 0x00;
//发送起始信号+设备地址+写信号
I2CTXD = SLAW;
I2CMSCR = 0x09;
while ((I2CMSST & 0x40) == 0);
I2CMSST = 0x00;
//发送存储器地址
I2CTXD = addr;
I2CMSCR = 0x0a;
while ((I2CMSST & 0x40) == 0);
I2CMSST = 0x00;
//发送起始信号+设备地址+读信号
I2CTXD = SLAR;
I2CMSCR = 0x09;
while ((I2CMSST & 0x40) == 0);
I2CMSST = 0x00;
DmaRxFlag = 1;
//触发数据读取命令
I2CMSCR = 0x8b;
DMA_I2C_CR = 0x01;
DMA_I2CR_AMT = number-1; //设置传输总字节数(低8位):n+1
DMA_I2CR_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_I2C_ST1 = number-1; //设置需要传输字节数(低8位):number + 设备地址 + 存储地址
DMA_I2C_ST2 = 0x00; //设置需要传输字节数(高8位):n+1
DMA_I2CR_CR |= 0x40; //bit7 1:使能 I2CT_DMA, bit5 1:开始 I2CT_DMA, bit0 1:清除 FIFO
while(DmaRxFlag); //DMA忙检测
DMA_I2C_CR = 0x00;
}
//========================================================================
// 函数: void I2C_DMA_Interrupt (void) interrupt 60/61
// 描述: I2C DMA中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-5-8
// 备注:
//========================================================================
void I2C_DMA_Interrupt(void) interrupt 13
{
if(DMA_I2CT_STA & 0x01) //发送完成
{
DMA_I2CT_STA &= ~0x01; //清除标志位
DmaTxFlag = 0;
}
if(DMA_I2CT_STA & 0x04) //数据覆盖
{
DMA_I2CT_STA &= ~0x04; //清除标志位
}
if(DMA_I2CR_STA & 0x01) //接收完成
{
DMA_I2CR_STA &= ~0x01; //清除标志位
DmaRxFlag = 0;
}
if(DMA_I2CR_STA & 0x02) //数据丢弃
{
DMA_I2CR_STA &= ~0x02; //清除标志位
}
}
//========================================================================
// 函数: void I2C_Interrupt (void) interrupt 24
// 描述: I2C 中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-3-18
// 备注:
//========================================================================
void I2C_Interrupt() interrupt 24
{
I2CMSST &= ~0x40; //I2C指令发送完成状态清除
if(DMA_I2C_CR & 0x04) //ACKERR
{
DMA_I2C_CR &= ~0x04; //发数据后收到NAK
}
}
66-DMA-I2C主机模式读写AT24C02-串口监控.zip
(11.36 KB, 下载次数: 1)
|
|