- 打卡等级:常住居民I
- 打卡总天数:78
- 最近打卡:2026-07-21 13:27:09
已绑定手机
版主
- 积分
- 1069
|
60-DMA-I2C与存储器数据自动收发,STC32G144K246实验箱演示程序
主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com -----------------------------------------*/
/*---------------------------------------------------------------------*/
/************* 本程序功能说明 **************
本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
串口发指令通过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范围.
下载时, 选择时钟 48MHz (用户可自行修改频率).
******************************************/
#include "../comm/STC32G144K246.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**************** 用户定义宏 ****************/
#define MAIN_Fosc 48000000UL
#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
/**************** IO口定义 ******************/
#define WP_DISABLE() P9CLRB = 0x10 //P94 = 0
#define WP_ENABLE() P9SETB = 0x10 //P94 = 1
/**************** 本地变量声明 **************/
u8 EEPROM_addr;
u8 xdata DmaTxBuffer[256];
u8 xdata DmaRxBuffer[256];
u16 RX1_Cnt; //接收计数
bit B_TX1_Busy; //发送忙标志
bit DmaTxFlag=0;
bit DmaRxFlag=0;
bit B_RX1_TimeOut; //接收超时标志
u8 RX1_Buffer[UART1_BUF_LENGTH]; //接收缓冲
/**************** 本地函数声明 **************/
void UartInit(void);
void I2C_init(void);
void WriteNbyte(u8 addr, u8 number);
void ReadNbyte( u8 addr, u8 number);
void delay_ms(u16 ms);
void RX1_Check(void);
void DMA_Config(void);
/**********************************************/
void main(void)
{
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 1; //避免 DMA 与 CPU 同时访问 xdata 时产生总线冲突
P7M1 = 0x00; P7M0 = 0x80; //P77设置为推挽输出
P9M1 = 0x00; P9M0 = 0x10; //P94设置为推挽输出
P3M1 = 0x00; P3M0 = 0x02; //设置P3.1推挽输出
P7PU |= 0x40; //P76内部上拉使能
I2C_init();
UartInit();
DMA_Config();
EA = 1; //允许总中断
WP_DISABLE();
printf("命令设置:\r\n");
printf("W 0x10 12345678 --> 写入操作 十六进制地址 写入内容\r\n");
printf("R 0x10 8 --> 读出操作 十六进制地址 读出字节内容\r\n");
while(1)
{
if(B_RX1_TimeOut)
{
B_RX1_TimeOut = 0;
if(RX1_Cnt > 0)
{
RX1_Check(); //串口1处理数据
}
RX1_Cnt = 0;
}
}
}
//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注: 由于芯片使能了Cache功能,软件延时时间可能不太准确
//========================================================================
void delay_ms(u16 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;
}
if(TI)
{
TI = 0; //Clear Tx flag
B_TX1_Busy = 0;
}
if(UR1TOSR & 0x01)
{
B_RX1_TimeOut = 1;
UR1TOSR = 0x80; //设置 RTOCF 清除超时标志位 TOIF
}
}
/********************** I2C函数 ************************/
void I2C_init(void)
{
I2C_S1 = 1; //I2C1功能脚选择,00:P1.5,P1.4; 01:P2.5,P2.4; 10:P7.7,P7.6; 11:P3.2,P3.3
I2C_S0 = 0;
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 I2CT_DMA_Interrupt(void) interrupt DMA_I2CT_VECTOR
{
if(DMA_I2CT_STA & 0x01) //发送完成
{
DMA_I2CT_STA &= ~0x01; //清除标志位
DmaTxFlag = 0;
}
if(DMA_I2CT_STA & 0x04) //数据覆盖
{
DMA_I2CT_STA &= ~0x04; //清除标志位
}
}
void I2CR_DMA_Interrupt(void) interrupt DMA_I2CR_VECTOR
{
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 I2C_VECTOR
{
I2CMSST &= ~0x40; //I2C指令发送完成状态清除
if(DMA_I2C_CR & 0x04) //ACKERR
{
DMA_I2C_CR &= ~0x04; //发数据后收到NAK
}
}
/******************** 串口打印函数 ********************/
void UartInit(void)
{
S1_S1 = 0; //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
S1_S0 = 0;
SCON = (SCON & 0x3f) | 0x40;
T1x12 = 1; //定时器时钟1T模式
S1BRT = 0; //串口1选择定时器1为波特率发生器
TL1 = TM;
TH1 = TM>>8;
TR1 = 1; //定时器1开始计时
// SCON = (SCON & 0x3f) | 0x40;
// T2L = TM;
// T2H = TM>>8;
// AUXR |= 0x15; //串口1选择定时器2为波特率发生器
UR1TOCR = 0xc0; //bit7:使能超时接收,bit6:使能超时中断,bit5:超时时钟选择 1:系统时钟 0:串口数据位率(波特率)
UR1TOTL = 0x20;
UR1TOTH = 0x00; //0x5666 = 22118
UR1TOTE = 0x00; //需要写 UR1TOTE 后,新的TM值才会生效
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;
}
60-DMA-I2C与存储器数据自动收发.zip
(13.23 KB, 下载次数: 0)
|
|