xxkj2010
发表于 2025-2-21 10:38:26
谢谢分享!
durongze
发表于 2025-2-23 09:35:58
大佬,官方的AI8051U.H里面 有c51的语法,像下面这个unsigned char volatile far 这个在sdcc里面对应的是啥,你知道不?
是不是__sfr __at(0x7efeb0) PWMA_ETRPS?好像不对。会报地址超出的问题。
#define PWMA_ETRPS (*(unsigned char volatile far *)0x7efeb0)
#define PWMA_ENO (*(unsigned char volatile far *)0x7efeb1)
#define PWMA_PS (*(unsigned char volatile far *)0x7efeb2)
#define PWMA_IOAUX (*(unsigned char volatile far *)0x7efeb3)
#define PWMB_ETRPS (*(unsigned char volatile far *)0x7efeb4)
#define PWMB_ENO (*(unsigned char volatile far *)0x7efeb5)
#define PWMB_PS (*(unsigned char volatile far *)0x7efeb6)
#define PWMB_IOAUX (*(unsigned char volatile far *)0x7efeb7)
#define PWMA_PS2 (*(unsigned char volatile far *)0x7efeb8)
#define PWMA_RCRH (*(unsigned char volatile far *)0x7efeb9)
#define PWMB_RCRH (*(unsigned char volatile far *)0x7efeba)
#define PWMA_CR1 (*(unsigned char volatile far *)0x7efec0)
#define PWMA_CR2 (*(unsigned char volatile far *)0x7efec1)
#define PWMA_SMCR (*(unsigned char volatile far *)0x7efec2)
#define PWMA_ETR (*(unsigned char volatile far *)0x7efec3)
#define PWMA_IER (*(unsigned char volatile far *)0x7efec4)
#define PWMA_SR1 (*(unsigned char volatile far *)0x7efec5)
#define PWMA_SR2 (*(unsigned char volatile far *)0x7efec6)
#define PWMA_EGR (*(unsigned char volatile far *)0x7efec7)
#define PWMA_CCMR1 (*(unsigned char volatile far *)0x7efec8)
#define PWMA_CCMR2 (*(unsigned char volatile far *)0x7efec9)
#define PWMA_CCMR3 (*(unsigned char volatile far *)0x7efeca)
#define PWMA_CCMR4 (*(unsigned char volatile far *)0x7efecb)
#define PWMA_CCER1 (*(unsigned char volatile far *)0x7efecc)
#define PWMA_CCER2 (*(unsigned char volatile far *)0x7efecd)
#define PWMA_CNTRH (*(unsigned char volatile far *)0x7efece)
#define PWMA_CNTRL (*(unsigned char volatile far *)0x7efecf)
#define PWMA_PSCRH (*(unsigned char volatile far *)0x7efed0)
#define PWMA_PSCRL (*(unsigned char volatile far *)0x7efed1)
#define PWMA_ARRH (*(unsigned char volatile far *)0x7efed2)
#define PWMA_ARRL (*(unsigned char volatile far *)0x7efed3)
#define PWMA_RCR (*(unsigned char volatile far *)0x7efed4)
#define PWMA_CCR1H (*(unsigned char volatile far *)0x7efed5)
#define PWMA_CCR1L (*(unsigned char volatile far *)0x7efed6)
#define PWMA_CCR2H (*(unsigned char volatile far *)0x7efed7)
#define PWMA_CCR2L (*(unsigned char volatile far *)0x7efed8)
#define PWMA_CCR3H (*(unsigned char volatile far *)0x7efed9)
#define PWMA_CCR3L (*(unsigned char volatile far *)0x7efeda)
#define PWMA_CCR4H (*(unsigned char volatile far *)0x7efedb)
#define PWMA_CCR4L (*(unsigned char volatile far *)0x7efedc)
#define PWMA_BKR (*(unsigned char volatile far *)0x7efedd)
#define PWMA_DTR (*(unsigned char volatile far *)0x7efede)
#define PWMA_OISR (*(unsigned char volatile far *)0x7efedf)
ercircle
发表于 2025-2-23 10:46:32
durongze 发表于 2025-2-23 09:35
大佬,官方的AI8051U.H里面 有c51的语法,像下面这个unsigned char volatile far 这个在sdcc里面对 ...
你看我发的源码里搜下,对应这个:
#define PWMA_ETRPS (*(unsigned char volatile __xdata *)0xfeb0)
durongze
发表于 2025-2-23 11:27:01
ercircle 发表于 2025-2-23 10:46
你看我发的源码里搜下,对应这个:
#define PWMA_ETRPS (*(unsigned char volatile __x ...
刚刚重新看了一下。我知道了。多谢。
durongze
发表于 2025-2-23 11:36:15
我往你的工程里加了一个红外的,直接把你的工程搞崩了。 {:ciya:}{:hanxiao:}
想要跟着你的步法,还是任重而道远。
---------------------------------------------------------------------------------
case VK_DIGIT_0:
// printf("00000000"); //在数码管上显示字符串
IrWave(rawDataAirOn1, sizeof(rawDataAirOn1) / sizeof(rawDataAirOn1));
break;
case VK_DIGIT_1:
// printf("%08lx", 0x1234abcdL); //在数码管上显示字符串
IrWave(rawDataAirOn2, sizeof(rawDataAirOn2) / sizeof(rawDataAirOn2));
break;
case VK_DIGIT_2:
// SEG7_ShowLong(0x98765432, 16); //在数码管上显示4字节长整型数
IrWave(rawDataAirOn3, sizeof(rawDataAirOn3) / sizeof(rawDataAirOn3));
break;
-------------------------------------------------------------------------
#ifndef __IR_AIR_H__
#define __IR_AIR_H__
#include "ir_air.h"
#include "Ai8051U.h"
typedef unsigned int u16;
static volatile u16 tx_cnt; //发送或空闲的脉冲计数(等于38KHZ的脉冲数,对应时间), 红外频率为38KHZ, 周期26.3us
void PWM_config(void)
{
PWMA_CCER2 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道
PWMA_CCMR4 = 0x60; //设置 PWM4 模式1 输出
//PWMA_CCER2 = 0xB0; //使能 CC4E 通道, 低电平有效
PWMA_ARRH = 0x02;//设置周期时间
PWMA_ARRL = 0x77;
PWMA_CCR4H = 0;
PWMA_CCR4L = 210;//设置占空比时间
PWMA_PS = 0x80; //高级 PWM 通道 4N 输出脚选择位, 0x00:P1.7, 0x40:P0.7, 0x80:P2.7
//PWMA_PS = 0x80; //高级 PWM 通道 4P 输出脚选择位, 0x00:P1.6, 0x40:P0.6, 0x80:P2.6
PWMA_ENO = 0x80; //使能 PWM4N 输出
//PWMA_ENO = 0x40; //使能 PWM4P 输出
PWMA_BKR = 0x80; //使能主输出
//PWMA_IER = 0x10; //使能中断
PWMA_CR1 |= 0x81;//使能ARR预装载,开始计时
}
void PWMA_ISR() __interrupt(PWMA_VECTOR)
{
if(PWMA_SR1 & 0X10)
{
PWMA_SR1 &=~0X10;
// PWMA_SR1 = 0;
if(--tx_cnt == 0)
{
PWMA_CCER2 = 0x00; // 写 CCMRx 前必须先清零 CCxE 关闭通道
PWMA_CCMR4 = 0x40; // 设置 PWM4 强制为无效电平
PWMA_CCER2 = 0x70; // 使能 CC4NE 通道, 低电平有效
PWMA_IER = 0x00; // 关闭中断
}
}
}
void IR_TxPulse(u16 pulse)
{
tx_cnt = pulse;
PWMA_CCER2 = 0x00; //
PWMA_CCMR4 = 0x60; //
PWMA_CCER2 = 0x70; //
PWMA_IER = 0x10; //
while(tx_cnt);
}
void IR_TxSpace(u16 pulse)
{
tx_cnt = pulse;
PWMA_CCER2 = 0x00; //
PWMA_CCMR4 = 0x40; //
PWMA_CCER2 = 0x70; //
PWMA_IER = 0x10; //
while(tx_cnt);
}
void IrWave(u16 *raw, int rawNum)
{
int i;
for(i = 0; i < rawNum; i++)
{
if (i % 2 == 0) {
IR_TxPulse(raw/1000*38);
} else {
IR_TxSpace(raw/1000*38);
}
}
}
#endif
ercircle
发表于 2025-2-23 11:51:09
durongze 发表于 2025-2-23 11:36
我往你的工程里加了一个红外的,直接把你的工程搞崩了。
想要跟着你的步法,还是任重而道远。
夸张了,慢慢来呗{:4_197:}搞不定了工程贴上来大家一块研究研究
durongze
发表于 2025-2-23 12:25:47
ercircle 发表于 2025-2-23 11:51
夸张了,慢慢来呗搞不定了工程贴上来大家一块研究研究
我增加了两个文件Library/ir_air.cLibrary/ir_air.h
其实 Library/ir_air.c 中只有void IrWave(u16 *raw, int rawNum)这个函数是我写的,其他的代码是我从官网的例子里 复制过来的。
从字面意思来看比较简单,就是 用 红外的 脉冲 和 空闲 两个函数把 main.c 中的 rawDataAirOn1 发出去。
然后在 User/Main.c 里面调用了一下。
#include "stdio.h"
#define PRINTF_HID
//#define PRINTF_SEGLED //printf输出重定向到ISP下载软件中的7段数码管
#include "AI8051U.h"//包含此头文件后,不需要再包含"reg51.h"头文件
#include "usb.h" //USB调试及复位所需头文件
#include "vk.h"
#include "pic.h"
#include "string.h"
#include "ir_air.h"
#define MAIN_Fosc 24000000L //定义主时钟
BYTE xdata cod;
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#"; //设置自动复位到ISP区的用户接口命令
u16 rawDataAirOn1 = {6122, 7424,514, 1674,514, 1674,514, 1676,514, 1674,514, 1674,514, 1676,512, 1676,514, 1674,514, 580,514, 580,514, 580,514, 580,514, 578,514, 580,514, 580,514, 578,514, 1676,514, 1674,514, 1674,514, 1674,514, 1676,512, 1674,514, 1674,514, 1676,514, 578,514, 580,514, 582,512, 582,512, 580,514, 580,514, 580,514, 580,514, 1676,514, 1674,514, 1674,514, 1674,514, 1676,514, 1672,514, 1674,514, 1674,514, 580,512, 580,514, 578,514, 580,512, 582,514, 580,514, 580,514, 580,514, 1674,514, 580,514, 1674,514, 580,514, 580,514, 580,512, 582,514, 1676,512, 580,514, 1674,514, 580,514, 1676,512, 1676,512, 1674,512, 1676,512, 582,514, 580,512, 1676,512, 1676,536, 558,534, 1654,512, 582,536, 1654,534, 1652,534, 1654,536, 558,534, 558,534, 1654,536, 558,534, 1654,534, 558,534, 560,534, 560,536, 1652,534, 562,534, 1652,514, 582,512, 1676,512, 582,512, 582,512, 1674,536, 560,512, 1674,536, 560,512, 1674,512, 584,512, 1676,512, 1678,512, 7408,512};
u16 rawDataAirOn2 = {3410, 1670,408, 1258,410, 1260,408, 424,408, 426,408, 424,410, 1258,408, 426,408, 424,408, 1258,432, 1236,408, 424,430, 1236,408, 426,408, 424,408, 1258,408, 1258,432, 402,408, 1260,408, 1258,408, 426,408, 424,408, 1260,408, 424,408, 424,408, 1258,408, 424,408, 426,430, 404,430, 402,408, 424,408, 426,408, 426,430, 402,408, 426,408, 426,430, 402,430, 402,408, 426,408, 426,408, 426,408, 426,408, 426,430, 1236,430, 404,408, 424,408, 1260,430, 404,408, 424,408, 1260,408, 1260,430, 404,430, 404,430, 402,430, 404,430, 402,430, 402,430, 402,430, 1236,408, 1260,430, 404,430, 402,430, 402,430, 404,430, 404,430, 402,430, 1236,430, 402,430, 1238,430, 1236,430, 1236,430, 404,430, 404,430, 404,430, 402,430, 404,430, 404,430, 404,430, 404,430, 404,430, 404,430, 402,430, 404,430, 402,430, 404,430, 404,430, 404,430, 402,430, 402,430, 404,430, 404,430, 404,406, 426,430, 404,430, 402,428, 404,428, 404,430, 404,430, 404,430, 404,430, 404,428, 404,428, 404,430, 404,430, 404,430, 404,406, 426,430, 1236,430, 1238,430, 1238,430, 1236,408, 1260,430, 404,406};
u16 rawDataAirOn3 = {3492, 1746,458, 1310,462, 372,460, 374,460, 372,460, 1312,460, 396,436, 398,434, 400,436, 1310,460, 398,436, 374,460, 398,434, 1312,460, 398,434, 398,434, 398,434, 1314,458, 398,436, 398,436, 398,436, 1312,460, 372,460, 374,460, 400,434, 1310,460, 400,434, 398,434, 374,460, 1310,460, 398,434, 374,460, 372,460, 1312,460, 372,460, 374,460, 372,460, 1310,462, 370,460, 374,460, 374,460, 374,460, 374,460, 1310,460, 374,460, 374,460, 1312,460, 374,460, 372,460, 1310,460, 1312,460, 372,460, 372,460, 374,460, 372,460, 374,460, 374,460, 374,458, 1312,460, 1310,460, 372,460, 374,460, 372,460, 374,460, 372,460, 374,460, 1312,482, 350,482, 1290,482, 352,482, 350,484, 350,490, 370,462, 372,458, 376,456, 376,458, 376,456, 374,456, 376,458, 376,456, 376,456, 376,456, 376,456, 376,456, 376,456, 376,456, 378,456, 378,456, 378,456, 378,454, 402,430, 402,408, 426,430, 404,408, 426,408, 426,408, 426,408, 426,408, 424,408, 426,430, 378,454, 378,456, 378,456, 376,456, 376,456, 374,458, 376,458, 1314,458, 1314,458, 374,456, 376,458, 376,458, 1314,456};
//P3.2口按键复位所需变量
bit Key_Flag;
u16 Key_cnt;
void sys_init();
void delay_ms(u8 ms);
void KeyResetScan(void);
// PUTCHAR_FUN(){
// USB_SendData((BYTE*)&c,1);
// return c;
// }
void main()
{
sys_init();
usb_init();
PWM_config();
EA = 1;
while (1)
{
delay_ms(1);
KeyResetScan(); //长按P3.2口按键触发软件复位,进入USB下载模式,不需要此功能可删除本行代码
if(DeviceState != DEVSTATE_CONFIGURED)//判断USB设备是否配置完成
continue;
if (bUsbOutReady)
{
if ((UsbOutBuffer == 'K') &&
(UsbOutBuffer == 'E') &&
(UsbOutBuffer == 'Y') &&
(UsbOutBuffer == 'P'))
{
switch (UsbOutBuffer)
{
case VK_DIGIT_0:
// printf("00000000"); //在数码管上显示字符串
IrWave(rawDataAirOn1, sizeof(rawDataAirOn1) / sizeof(rawDataAirOn1));
break;
case VK_DIGIT_1:
// printf("%08lx", 0x1234abcdL); //在数码管上显示字符串
IrWave(rawDataAirOn2, sizeof(rawDataAirOn2) / sizeof(rawDataAirOn2));
break;
case VK_DIGIT_2:
// SEG7_ShowLong(0x98765432, 16); //在数码管上显示4字节长整型数
IrWave(rawDataAirOn3, sizeof(rawDataAirOn3) / sizeof(rawDataAirOn3));
break;
---------------------------------------------------------------------------------------------------------
durongze
发表于 2025-2-23 12:32:15
void IrWave(u16 *raw, int rawNum)
{
int i;
for(i = 0; i < rawNum; i++)
{
if (i % 2 == 0) {
IR_TxPulse(raw/1000*38); //我简单解释一下为啥要除以1000,这个是把us转成ms,成以38是我发现官网的例子里似乎是把毫秒乘以38才往出发。
} else {
IR_TxSpace(raw/1000*38);
}
}
}
----------------------------------------------------
下面这段代码是官网给的例子里的,我分析了官网的代码,发现这个接口传的值应该是ms值*38
if (KeyCode != 0) //检测到键码
{
KeyCode=255;
TxTime = 0;
//一帧数据最小长度 = 9 + 4.5 + 0.5625 + 24 * 1.125 + 8 * 2.25 = 59.0625 ms
//一帧数据最大长度 = 9 + 4.5 + 0.5625 + 8 * 1.125 + 24 * 2.25 = 77.0625 ms
IR_TxPulse(342); //对应9ms,同步头 9ms 这里的342 应该就是9 *38 得来的
IR_TxSpace(171); //对应4.5ms,同步头间隔 4.5ms这里的171 应该就是4.5*38 得来的
IR_TxPulse(21); //开始发送数据 0.5625ms 这里的21 应该就是0.5625*38 得来的
IR_TxByte(User_code%256); //发用户码低字节
IR_TxByte(User_code/256); //发用户码高字节
IR_TxByte(KeyCode); //发数据
IR_TxByte(~KeyCode); //发数据反码
if (TxTime < 56) //一帧按最大77ms发送, 不够的话,补偿时间 108ms
{
TxTime = 56 - TxTime;
TxTime = TxTime + TxTime / 8;
delay_ms(TxTime);
}
delay_ms(31);
while (IO_KeyState != 0) //键未释放
{
IR_TxPulse(342); //对应9ms, 同步头 9ms
IR_TxSpace(86); //对应2.25ms,同步头间隔 2.25ms
IR_TxPulse(21); //开始发送数据 0.5625ms
delay_ms(96);
IO_KeyScan();
}
printf("User_code=0x%04X,KeyCode=%u\r\n", User_code, KeyCode);
KeyCode = 0;
}
ercircle
发表于 2025-2-23 12:58:08
sdcc要在main函数所在文件声明中断中断才生效。和keil的差异点可以参考我这个帖子
【四合一】分享一个可同时编译Keil C251\Keil C51\SDCC\IAR工程模板 - SDCC, IAR C++ for 51, GCC, VSCode,Linux, MacOS 国芯技术交流网站 - AI32位8051交流社区
建议:
业务代码放在sdcc工程,不要放在lib工程,否则每次修改后要重新编译两个工程。
编译前clean缓存:
make clean
make
另外修改了几处可能是bug,你试下
这两行验证不阻塞了:
durongze
发表于 2025-2-23 13:28:40
ercircle 发表于 2025-2-23 12:58
sdcc要在main函数所在文件声明中断中断才生效。和keil的差异点可以参考我这个帖子
【四合一】分享一个可同 ...
官网的例子里有个bug,我也往里面加了两个bug 。{:yinxian:}
1.extern void PWMA_ISR() __interrupt(PWMA_VECTOR); //这个是我改出来的。
2.tx_cnt--; // 等于0的时候继续--,这个bug是官网原来的。
3.IR_TxPulse(raw/1000.0*38); // 这个除法的大bug 也是我搞出来的。{:hanxiao:}