|

楼主 |
发表于 2024-12-24 21:44:53
|
显示全部楼层
因为x轴(水平)范围是0~168,y轴(垂直)范围是0~120,亮度范围是0~256,所以3个dac的分辨率只要8bit即可,stm32的dac刚好也提供了8bit的分辨率的选项,但是如果后续要提高分辨率的话,dac就要设置为12bit了
dac生成锯齿波的基本思路是由单片机主时钟,经过定时器分频后得到x轴和z轴dac触发时钟,这个时钟再分频,得到y轴触发时钟,这三个时钟分别触发对应的dac,同时dma将指定地点的数组数据依次搬运到dac中,dma搬运到数组末尾后又自动跳回数组头部,整个过程周而复始,不需要cpu介入,cpu只需要操作z轴dac对应的数组,也就是显存,在这个显存里就可以完成各种各样的显示和画图操作。
行频设置为10kHz,那么x轴dac触发的时钟为168像素*10kHz=1.68MHz,场频设置为83.33Hz,那么y轴dac触发的时钟为120像素*83.33Hz=10kHz,z轴dac的触发频率和x轴一样也是1.68MHz
在这里把单片机的时钟设置为168MHz,就可以通过定时器分频获得这些时钟。
部分代码:
struct
{
uint8_t TV_mode_X_buf[CRT_WIDTH_X];//x轴dac的数据数组
uint8_t TV_mode_Y_buf[CRT_HEIGHT_Y];//y轴dac的数据数组
uint8_t CRT_VRAM[CRT_WIDTH_X*CRT_HEIGHT_Y];//显存
}CRT;
void CRT_TV_mode_init(bool rotate_x, bool rotate_y)//选择是否反转x或y轴
{
uint8_t i,j;
for(i=0;i<CRT_WIDTH_X;i++)
{
CRT.TV_mode_X_buf[i]=rotate_x ? 255-(i+50) : i+50;//生成锯齿波数据
}
for(j=0;j<CRT_HEIGHT_Y;j++)
{
CRT.TV_mode_Y_buf[j]=rotate_y ? 255-(j*2) : j*2+15;//生成锯齿波数据
}
HAL_OPAMP_SelfCalibrate(&hopamp1);//校准片内运放
HAL_OPAMP_Start(&hopamp1);//启动片内运放
}
void CRT_TV_mode_start_XY_scan(void)
{
__HAL_TIM_SET_COUNTER(&htim3,0);//定时器初始值清零
__HAL_TIM_SET_COUNTER(&htim2,0);//定时器初始值清零
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)CRT.TV_mode_Y_buf, CRT_HEIGHT_Y, DAC_ALIGN_8B_R);//启动y轴dac和dma生成锯齿波
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t*)CRT.TV_mode_X_buf, CRT_WIDTH_X, DAC_ALIGN_8B_R);//启动x轴dac和dma生成锯齿波
HAL_DAC_Start_DMA(&hdac3, DAC_CHANNEL_1, (uint32_t*)(CRT.CRT_VRAM), CRT_VRAM_SIZE, DAC_ALIGN_8B_R);//启动z轴dac和dma生成亮度信号
HAL_TIM_Base_Start_IT(&htim3);//10kHz的定时器,用于触发y轴dac
HAL_Delay(0);
HAL_TIM_Base_Start(&htim2);//1.68MHz的定时器,用于触发x和z轴dac
}
(由于在芯片上,z轴dac(dac3)没有直接的管脚引出,只能通过片内的运放作为跟随器连接到外部,) |
|