页次: 1
9.底层的TIMER_GET_MAIN_CNT_RP函数有bug,返回值为2和3,官方技术推荐使用TIMER_GET_MAIN_CNT_ALL函数替代TIMER_GET_MAIN_CNT_RP和TIMER_GET_MAIN_CNT_ALL
//推荐使用这个
#define TIMER_GET_MAIN_CNT_ALL(TIMER_SEL,main_cnt,main_cnt_rp) main_cnt = (*(volatile u32*)(TIMER_SEL+0x12*8));\
main_cnt_rp = main_cnt>>24;\
main_cnt = main_cnt&0x00ffffff
//有bug
#define TIMER_GET_MAIN_CNT_RP(TIMER_SEL,main_cnt_rp) main_cnt_rp = (*(volatile u8*)(TIMER_SEL+0x11*8))
#define TIMER_GET_MAIN_CNT(TIMER_SEL,main_cnt) main_cnt = (*(volatile u32*)(TIMER_SEL+0x10*8))
[XMG助力国产生态]
@XMGroupe.
本文介绍使用MC3172实现基于三角波调制的带死区的互补PWM产生方法。
常见的PWM调制方法有三种,即向上计数 向下计数 向上-向下计数,此demo使用向上向下计数,MC3172的PWM输出方法比较灵活,能够满足不同的需要,但是其每个timer只有四个compare让其使用存在一定局限,希望下一代能够增加到至少六个compare。
1.初始化
此demo使用timer3的P0和P1当作EPWM的P和N。
#define Dead_time 1000 //死区时间设置
void Pwm_Init(u32 timer_sel,u32 Arr,u32 Cmp)
{
INTDEV_SET_CLK_RST(timer_sel,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK));
TIMER_SET_OVERRIDE_GPIO(timer_sel,(TIMER_P3_OVERRIDE_GPIO|TIMER_P3_PULL_UP| \
TIMER_P2_OVERRIDE_GPIO|TIMER_P2_PULL_UP| \
TIMER_P1_OVERRIDE_GPIO|TIMER_P1_PULL_UP| \
TIMER_P0_OVERRIDE_GPIO|TIMER_P0_PULL_UP) \
);
TIMER_SET_OUTPUT_EN(timer_sel,(TIMER_P0_OUTPUT_ENABLE |TIMER_P1_OUTPUT_ENABLE |TIMER_P2_OUTPUT_ENABLE |TIMER_P3_OUTPUT_ENABLE| \
));
//分为四组,做两对互补
TIMER_SET_OUT_PORT(timer_sel,(TIMER_P0_IS_COMPARER0|TIMER_P1_IS_COMPARER1| \
TIMER_P2_IS_COMPARER2|TIMER_P3_IS_COMPARER3| \
));
TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE|TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_NOT_FORCE));
//下面四条用于控制频率
TIMER_SET_MAIN_CNT_BEGIN_VALUE0(timer_sel,TIMER_MAIN_CNT_COUNT_UP,0);
TIMER_SET_MAIN_CNT_END_VALUE0(timer_sel,Arr);
TIMER_SET_MAIN_CNT_BEGIN_VALUE1(timer_sel,TIMER_MAIN_CNT_COUNT_DOWN,Arr);
TIMER_SET_MAIN_CNT_END_VALUE1(timer_sel,0);
TIMER_SET_CMD(timer_sel,TIMER_CMD_RESTART);
TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
TIMER_SET_CMD(timer_sel,TIMER_CMD_RUN);
}
需要注意,采用向上-向下计数方法,其PWM频率为 系统频率/ARR/2,因此死区时间为 Dead_time * (2/系统频率)
此实验采用200M外部有源晶振,因此demo的PWM频率为100 000 000/ARR,死区时间为 1000*10ns = 10us(正常不需要这么大,此处为了验证EPWM在大占空比时能否实现强制输出)。
2.占空比修改函数
void Set_PWM_Duty(u32 timer_sel,u32 Arr,float Duty1)
{
static u8 flag_set = 0;
static float Duty_old = 0.0;
static u32 Compare_old = 0;
static u32 Cmp = 0;
u32 CNT = 0;
u8 RP = 0;
if(Duty_old != Duty1)
{
Duty_old = Duty1;
Cmp = (u32)(Duty1*Arr);
flag_set = 0x80; //最高位置1,开启修改占空比
}
if((flag_set & 0x80) != 0) //判断最高位
{
if((Cmp > Dead_time)&&((Arr - Cmp) > Dead_time)) //P、N脚正常输出
{
TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_NOT_FORCE));
}
else if(Cmp <= Dead_time) //P脚关闭输出
{
TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
TIMER_COMPARER1_NOT_FORCE|TIMER_COMPARER0_FORCE0));
}
else if(((Arr - Cmp) <= Dead_time)) //N脚关闭输出
{
TIMER_SET_COMPARER_MODE(timer_sel,(TIMER_COMPARER3_NOT_FORCE|TIMER_COMPARER2_NOT_FORCE| \
TIMER_COMPARER1_FORCE0|TIMER_COMPARER0_NOT_FORCE));
}
TIMER_GET_MAIN_CNT_ALL(timer_sel,CNT,RP);
if(RP == 1) //不在规则区0,修改规则区0
{
if(flag_set == 0x80) //第一次修改
{
flag_set = 0x81; //修改标志位,规则0 次序1
//compare0
TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
//compare1
TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
}
else if(flag_set == 0x82) //第二修改
{
flag_set = 0; //修改标志位
//compare0
TIMER_SET_COMPARER0_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
TIMER_SET_COMPARER0_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp-Dead_time));
//compare1
TIMER_SET_COMPARER1_VALUE0_0(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
TIMER_SET_COMPARER1_VALUE0_1(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp+Dead_time));
}
}
//修改规则1区
else
{
if(flag_set == 0x80) //第一修改
{
flag_set = 0x82; //修改标志位,规则1 次序1
//compare0
TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
//compare1
TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
}
else if(flag_set == 0x81) //第二修改,修改结束
{
flag_set = 0; //修改标志位
//compare0
TIMER_SET_COMPARER0_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT1,(Cmp-Dead_time));
TIMER_SET_COMPARER0_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT0,0x00);
//compare1
TIMER_SET_COMPARER1_VALUE1_0(timer_sel,TIMER_COMPARER_OUTPUT0,(Cmp+Dead_time));
TIMER_SET_COMPARER1_VALUE1_1(timer_sel,TIMER_COMPARER_OUTPUT1,0x00);
}
}
}
}
上面的函数实现了EPWM的占空比设置和死区校验,防止出现占空比寄存数大于死区时间时输出高电平的现象。
3.输出PWM
输出的PWM如下图所示
在其占空比较小时,其输出电平被强制输出为低电平
[XMG助力国产生态]
@XMGroupe.
本文介绍MC3172普通IO模拟UART
此驱动通过软件延时实现,目前9600波特率能够稳定运行。
内部RC高速时钟 192M
1.初始化代码
typedef enum _TX_STATE_{
eUART_TX_IDLE = 0, //发送空闲
eUART_TX_SEND = 1, //发送数送
}eTX_STATE;
typedef struct _eUART_TX_{
eTX_STATE tx_state; //发送状态
u32 bound; //波特率
u8 nstop; //停止位数
}eUART_TX;
typedef enum _RX_STATE_{
eUART_RX_IDLE = 0, //接收空闲
eUART_RX_RECV = 1, //接收数据
}eRX_STATE;
typedef struct _eUART_RX_{
eTX_STATE rx_state; //发送状态
u32 bound; //波特率
u8 nstop; //停止位数
}eUART_RX;
eUART_TX exUART_TX;
eUART_RX exUART_RX;
void Uart_Soft_Init(u32 Rate)
{
/*启动外设*/
INTDEV_SET_CLK_RST(GPIOA_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));//24M
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_INPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN5),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
exUART_TX.bound = Rate;
exUART_TX.nstop = 1;
exUART_TX.tx_state = eUART_TX_IDLE;
}
2.发送程序
/*** euart开始位 ***/
/*
* baud 波特率
*/
void Send_Start_Soft(eUART_TX *extx)
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
delay_baud(extx->bound);
//GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN6));
}
/*** euar停止位 ***/
/*
* baud 波特率
* stop 停止位数
*/
void Send_Stop_Soft(eUART_TX *extx)
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
delay_baud(extx->bound);
}
/*** euart空闲 ***/
/*
* baud 波特率
* stop 停止位数
*/
void Send_Idle_Soft(eUART_TX *extx)
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
extx->tx_state = eUART_TX_IDLE; //空闲标志位置
}
//发送单个byte
void Send_Byte_Soft(unsigned char dat)
{
u8 i = 0;
while(exUART_TX.tx_state == eUART_TX_SEND); //等待总线空闲
if(exUART_TX.tx_state == eUART_TX_IDLE) //总线空闲
{
exUART_TX.tx_state = eUART_TX_SEND; //总线忙
Send_Start_Soft(&exUART_TX);
for(i = 0; i < 8; i++)
{
if(dat&0x01)
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
}
else
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
}
dat = dat >> 1;
delay_baud(exUART_TX.bound);
}
Send_Stop_Soft(&exUART_TX);
}
Send_Idle_Soft(&exUART_TX);
}
//发送字符串
void Send_String_Soft(u8 *dat, u16 len)
{
u8 temp = 0;
u16 send_count = 0;
u8 i = 0;
while(send_count < len)
{
exUART_TX.tx_state = eUART_TX_SEND; //总线忙
temp = dat[send_count];
Send_Start_Soft(&exUART_TX);
for(i = 0; i < 8; i++)
{
if(temp&0x01)
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,(GPIO_PIN4));
}
else
{
GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,(GPIO_PIN4),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,(GPIO_PIN4));
}
temp = temp >> 1;
delay_baud(exUART_TX.bound);
}
send_count ++;
Send_Stop_Soft(&exUART_TX);
}
Send_Idle_Soft(&exUART_TX);
}
3.接收函数
u8 Recv_String_Soft(u8 *recv, u16 len)
{
u8 i = 0;
u16 recv_count = 0;
u8 dat = 0x00;
while(recv_count < len)
{
//等待RX拉低,接收数据起始位
while(((GPIO_GET_INPUT_VALUE_FAST(GPIOA_BASE_ADDR)&0x0020)>>5) != 0);
//接收到起始位,设置为接收繁忙,延时波特率时间
exUART_RX.rx_state = eUART_RX_RECV;
delay_baud(exUART_TX.bound);
NOP();
for(i = 0; i < 8; i ++)
{
dat = dat >> 1;
if(((GPIO_GET_INPUT_VALUE_FAST(GPIOA_BASE_ADDR)&0x0020) >> 5) == 1)
{
dat |= 0x80;
}
delay_baud(exUART_TX.bound);
}
recv[recv_count] = dat;
dat = 0;
recv_count ++;
delay_baud(exUART_TX.bound); //延时一个停止位时间
}
return recv_count;
}
4.延时函数
void delay_baud(u32 baud)
{
u32 start,stop,ticks;
start = CORE_CNT;
if(baud == 9600)
{
ticks = 5002;
}
else
{
//其他波特率对应延时自行添加
//ticks = (u32)(Sys_Clk * 1000000 / baud);
}
if(0xFFFFFFFF-start>=ticks){
stop=start+ticks;
while(CORE_CNT<stop && CORE_CNT>start){}
}
else{
stop=ticks-(0xFFFFFFFF-start);
while(CORE_CNT>start){}
while(CORE_CNT<stop){}
}
}
最终效果
*程序还有很多可以优化的地方,比如接收函数可以添加接收超时,此贴只作为一个DEMO,欢迎大家批评指正。
*也希望起到抛砖引玉的效果,能够看到更多优秀的程序开源。
[XMG助力国产生态]
@XMGroupe.
本文介绍MC3172驱动DS18B20。
此驱动根据datasheet模拟实现。
1.初始化程序
#define DQ_Groupe GPIOD_BASE_ADDR
#define DQ_IO GPIO_PIN11
u8 DS18B20_Init(void)
{
u16 temp = 0;
u8 i = 0;
INTDEV_SET_CLK_RST(GPIOD_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2));
GPIO_SET_OUTPUT_EN_VALUE(GPIOD_BASE_ADDR,GPIO_PIN11,GPIO_SET_ENABLE);
//总线拉低 延时642us
GPIO_SET_OUTPUT_PIN_TO_0(GPIOD_BASE_ADDR,GPIO_PIN11);
delay_us(642);
//总线拉高,DS18B20会在15us后将总线拉低
GPIO_SET_OUTPUT_PIN_TO_1(GPIOD_BASE_ADDR,GPIO_PIN11);
delay_us(15);
GPIO_SET_INPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
temp = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;
while(temp)
{
temp = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;
delay_us(10);
i++;
if(i > 100)
{
return 0;
}
}
return 1;
}
2.读写字节
//读一个字节
u8 DS18B20_ReadByte(void)
{
u8 i = 0;
u16 dat = 0;
u8 byte = 0;
for(i = 8; i > 0; i --)
{
//先把总线拉低1us
GPIO_SET_OUTPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
delay_us(1);
//释放总线,延迟6us
GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
delay_us(6);
//读取数据
GPIO_SET_INPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
dat = (GPIO_GET_INPUT_VALUE_SAFE(DQ_Groupe) & 0x0800) >> 11;
byte = (byte >> 1) | (dat << 7);
//等待48us后读取下一位
delay_us(48);
}
return byte;
}
//写一个字节
void DS18B20_WriteByte(unsigned char dat)
{
u8 i = 0;
u16 temp = 0;
for(i = 8; i > 0; i --)
{
//写入每一位数据前先把总线拉低1us
GPIO_SET_OUTPUT_EN_VALUE(DQ_Groupe,DQ_IO,GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
delay_us(1);
//写入数据,低位开始
if(dat & 0x01)
{
GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
}
else
{
GPIO_SET_OUTPUT_PIN_TO_0(DQ_Groupe,DQ_IO);
}
dat = dat >> 1;
//总线数据持续60us
delay_us(60);
//释放总线,延时1us
GPIO_SET_OUTPUT_PIN_TO_1(DQ_Groupe,DQ_IO);
delay_us(1);
}
}
3.读取温度
int DS18B20_ReadTemp(void)
{
int temp = 0;
u8 tmh,tml;
//启动转换
DS18B20_Init();
delay_ms(1);
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0x44);
//发送温度读取指令
DS18B20_Init();
delay_ms(1);
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0xbe);
//读取温度
tml = DS18B20_ReadByte();
tmh = DS18B20_ReadByte();
temp = (tmh << 8) | tml;
return temp;
}
4.数据转换为浮点
float datatrans(int temp)
{
float temp_re = 0;
float tp;
if(temp < 0) //当温度值为负数
{
//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
temp = temp - 1;
temp = ~temp;
tp = temp;
temp_re = tp*0.0625+0.0005;//四舍五入
temp_re = temp_re * (-1);
}
else
{
tp = temp;
temp_re = tp*0.0625+0.0005;
}
return temp_re;
}
最终效果
[XMG助力国产生态]
@XMGroupe.
此贴记录了拿到核心板使用至今踩过的一些坑。
----------------------------------------------
0、IO口的常见配置在工程的GPIO_GPCOM_TIMER_Example.c文件中,一些常见操作可以参考或修改参数直接使用,如果不小心将其加入到了编译。只需要在对应.c文件上右键 点击 Include/Exclude From Build即可。
1、设置IO COM模式后,如果想要使用GPIO_GET_INPUT_VALUE_SAFE来读取IO的电平,需要同时使能COM对应的GPIO时钟
例如:
INTDEV_SET_CLK_RST(COMx,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
此处没有使能GPIOx_BASE_ADDR的时钟,
此时使用GPIO_GET_INPUT_VALUE_SAFE读取对应IO电平将得到全0值,
但是GPIO_GET_INPUT_VALUE_FAST可以正常使用。
INTDEV_SET_CLK_RST(COMx,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
INTDEV_SET_CLK_RST(GPIOx_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV8));
此处使能了GPIOx_BASE_ADDR的时钟,
此时使用GPIO_GET_INPUT_VALUE_SAFE和GPIO_GET_INPUT_VALUE_FAST均可读取对应IO电平。
2、使用GPIO_GET_INPUT_VALUE_XXXX读取的电平返回值是十六位无符号,请注意被赋值变量的位数是否合理。
3、MC3172.h文件中第212行存在一处bug,应修改为
#define GPIO_GET_INPUT_VALUE_FAST(GPIO_SEL) (*(volatile u16*)(GPIO_SEL+GPIO_READ_REAL_INPUT_VALUE_ADDR))
4、GPIO_SET_OUTPUT_PIN_VALUE用来设置IO的输出电平,其mask表示指定的IO口,value为16位输入,不要直接对value赋1或0进行设置
错误范例
GPIO_SET_OUTPUT_PIN_VALUE(GPIOA_BASE_ADDR,GPIO_PIN4,1);//A4设置为高电平
此处value值为0x0001,对应二进制 0000 0000 0000 0001,pin4为0
正确设置
GPIO_SET_OUTPUT_PIN_VALUE(GPIOA_BASE_ADDR,GPIO_PIN4,0x0010);//A4设置为高电平
5、有些功能需要IO口输入输出功能,参照51单片机,此处不必纠结太多,当需要在输入或输出切换时,只需要在对应的input函数或set函数前面加一句
GPIO_SET_OUTPUT_EN_VALUE(GPIOx_BASE_ADDR,GPIO_PINx,GPIO_SET_ENABLE);
GPIO_SET_INPUT_EN_VALUE(GPIOx_BASE_ADDR,GPIO_PINx,GPIO_SET_ENABLE);
即可。
6、外设速度与线程速度无关,在设置对应的外设COMx时,时钟分频是以系统主时钟进行分频的,与线程的频率无关,例如系统主时钟采用内部高速RC 192MHz,则在对COMx进行分频时,其分频基准为192M,与线程的1/4 1/8...无关。
7、断开USB线和核心板连接前,应先在烧写软件中进行断开连接操作,否则重新插入后烧写程序会无响应闪退。
*个人见解,不代表官方,如果有错误或描述不恰当的地方,欢迎官方和各位大佬批评指正。
*后面遇到新的坑会持续更新,
[XMG助力国产生态]
@XMGroupe.
本文介绍MC3172驱动SSD1306 OLED。
此驱动移植于STM32下的IIC驱动,对STM32工程中SSD1306OLED代码进行一些简单修改,完成OLED驱动。
修改内容:
1.更改IIC IO的初始化和控制函数;
void OLED_Gpio(void)
{
#ifdef OLED_ELOG
log_i("OLED Gpio Initing");
#endif
INTDEV_SET_CLK_RST(OLED_IOport,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV4));
GPIO_SET_OUTPUT_EN_VALUE(OLED_IOport,(OLED_Sclk|OLED_Sdin),GPIO_SET_ENABLE);
GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,(OLED_Sclk|OLED_Sdin));
#ifdef OLED_ELOG
log_i("OLED Gpio Init OK");
#endif
}
#define OLED_IOport GPIOA_BASE_ADDR
#define OLED_Sclk GPIO_PIN14
#define OLED_Sdin GPIO_PIN15
#define OLED_SCLK_Clr() GPIO_SET_OUTPUT_PIN_TO_0(OLED_IOport,OLED_Sclk);
#define OLED_SCLK_Set() GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,OLED_Sclk);
#define OLED_SDIN_Clr() GPIO_SET_OUTPUT_PIN_TO_0(OLED_IOport,OLED_Sdin);
#define OLED_SDIN_Set() GPIO_SET_OUTPUT_PIN_TO_1(OLED_IOport,OLED_Sdin);
2.根据MC3172的IO速度优化IIC的时许;
3.加入EasyLogger调试输出代码,其使能宏定义在oled.h文件中。
#define OLED_ELOG
驱动流程:
1.将OLED驱动文件(包括oled.c+oled.h+oledfont.h)加入到工程中;
2.在oled.h中修改对应的IO口
*注:此处默认为一组IO口,即CLK和SDA都是PAx,若采用两个不同组的IO,需要修改oled.h中的IO控制函数和oled.c中的初始化函数。
#define OLED_IOport GPIOA_BASE_ADDR
#define OLED_Sclk GPIO_PIN14
#define OLED_Sdin GPIO_PIN15
3.在线程中添加初始化代码
OLED_Init();
*程序只实现了一些基本的显示函数,其他显示功能与常规单片机一致,可以直接添加稍作修改后使用。
最终效果
[XMG助力国产生态]
@XMGroupe.
本文介绍MC3172移植EasyLogger教程。
本人从Github中下载EasyLogger源代码后,移植到MC3172时没有像移植到STM32那么顺利。
咨询感芯技术后得知,官方没有移植标准库,标准库的代码需要自己实现。
因此对EasyLogger源代码进行了一些修改:
1.移除了BUF和ASYNC;
2.标准库的函数在elog.c中进行了实现(能力有限,有些代码可能不是最优化版本);
3.标准库的变量在elog.h中进行了声明;
4.代码的打印分隔符已经修改完,移植完可以直接使用;
5.代码添加后需要进行printf重定向,头文件引用在elog.c中;
6.elog_port_output中已经添加了输出函数。
void elog_port_output(const char *log, size_t size) {
/* add your code here */
printf_("%.*s", size, log);
}
*printf重定向方法可以参照论坛中的帖子添加开源printf库。
*串口调试过程中出现的问题可以参照【调试记录】调整芯片主频之后串口需要修改串口初始化代码。
移植流程:
1.将修改后的EasyLogger文件夹放入工程中;
2.修改printf重定向函数引用,在elog.c中
#include "../USER_CODE/printf.h"
#include "../USER_CODE/uart.h"
3.配置线程,可以参考官方给出的极简开发手册
4.在主函数中引用elog.h的头文件
5.在线程中初始化elog函数,初始化方法可以参考如下代码
/* 初始化elog */
elog_init();
elog_set_text_color_enabled(true);//打开颜色模式
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO));
elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);
elog_start();
log_a("Hello EasyLogger!");
log_e("Hello EasyLogger!");
log_w("Hello EasyLogger!");
log_i("Hello EasyLogger!");
log_d("Hello EasyLogger!");
log_v("Hello EasyLogger!");
6.下载MobaXterm后配置端口进行测试
最终效果
页次: 1